code
This commit is contained in:
commit
141e914d03
1
Phaha_Cms
Submodule
1
Phaha_Cms
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 995a7e075edb35f551c60218897b67f8f4f9d36e
|
||||
16
Phaha_Package/.browserslistrc
Normal file
16
Phaha_Package/.browserslistrc
Normal file
@ -0,0 +1,16 @@
|
||||
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
|
||||
# For additional information regarding the format and rule options, please see:
|
||||
# https://github.com/browserslist/browserslist#queries
|
||||
|
||||
# For the full list of supported browsers by the Angular framework, please see:
|
||||
# https://angular.io/guide/browser-support
|
||||
|
||||
# You can see what browsers were selected by your queries by running:
|
||||
# npx browserslist
|
||||
|
||||
last 1 Chrome version
|
||||
last 1 Firefox version
|
||||
last 2 Edge major versions
|
||||
last 2 Safari major versions
|
||||
last 2 iOS major versions
|
||||
Firefox ESR
|
||||
16
Phaha_Package/.editorconfig
Normal file
16
Phaha_Package/.editorconfig
Normal file
@ -0,0 +1,16 @@
|
||||
# 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
|
||||
|
||||
[*.ts]
|
||||
quote_type = single
|
||||
|
||||
[*.md]
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
||||
48
Phaha_Package/.gitignore
vendored
Normal file
48
Phaha_Package/.gitignore
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# Compiled output
|
||||
/dist
|
||||
/tmp
|
||||
/out-tsc
|
||||
/bazel-out
|
||||
|
||||
# Node
|
||||
/node_modules
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
|
||||
# IDEs and editors
|
||||
.idea/
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# Visual Studio Code
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
.history/*
|
||||
|
||||
# Miscellaneous
|
||||
/.angular/cache
|
||||
.sass-cache/
|
||||
/connect.lock
|
||||
/coverage
|
||||
/libpeerconnection.log
|
||||
testem.log
|
||||
/typings
|
||||
|
||||
# System files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
src/environments/environment.ts
|
||||
yarn.lock
|
||||
src/environments/environment.ts
|
||||
.vs/
|
||||
4
Phaha_Package/.vscode/extensions.json
vendored
Normal file
4
Phaha_Package/.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
|
||||
"recommendations": ["angular.ng-template"]
|
||||
}
|
||||
20
Phaha_Package/.vscode/launch.json
vendored
Normal file
20
Phaha_Package/.vscode/launch.json
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "ng serve",
|
||||
"type": "pwa-chrome",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "npm: start",
|
||||
"url": "http://localhost:4200/"
|
||||
},
|
||||
{
|
||||
"name": "ng test",
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "npm: test",
|
||||
"url": "http://localhost:9876/debug.html"
|
||||
}
|
||||
]
|
||||
}
|
||||
4
Phaha_Package/.vscode/settings.json
vendored
Normal file
4
Phaha_Package/.vscode/settings.json
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"search.useGlobalIgnoreFiles": true,
|
||||
"search.useParentIgnoreFiles": true
|
||||
}
|
||||
42
Phaha_Package/.vscode/tasks.json
vendored
Normal file
42
Phaha_Package/.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
{
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "start",
|
||||
"isBackground": true,
|
||||
"problemMatcher": {
|
||||
"owner": "typescript",
|
||||
"pattern": "$tsc",
|
||||
"background": {
|
||||
"activeOnStart": true,
|
||||
"beginsPattern": {
|
||||
"regexp": "(.*?)"
|
||||
},
|
||||
"endsPattern": {
|
||||
"regexp": "bundle generation complete"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "test",
|
||||
"isBackground": true,
|
||||
"problemMatcher": {
|
||||
"owner": "typescript",
|
||||
"pattern": "$tsc",
|
||||
"background": {
|
||||
"activeOnStart": true,
|
||||
"beginsPattern": {
|
||||
"regexp": "(.*?)"
|
||||
},
|
||||
"endsPattern": {
|
||||
"regexp": "bundle generation complete"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
92
Phaha_Package/README.md
Normal file
92
Phaha_Package/README.md
Normal file
@ -0,0 +1,92 @@
|
||||
# VNPost - POSTENP
|
||||
|
||||
|
||||
|
||||
## Getting started
|
||||
|
||||
To make it easy for you to get started with GitLab, here's a list of recommended next steps.
|
||||
|
||||
Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)!
|
||||
|
||||
## Add your files
|
||||
|
||||
- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files
|
||||
- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command:
|
||||
|
||||
```
|
||||
cd existing_repo
|
||||
git remote add origin https://gitlab.com/service30/vnpost-postenp.git
|
||||
git branch -M main
|
||||
git push -uf origin main
|
||||
```
|
||||
|
||||
## Integrate with your tools
|
||||
|
||||
- [ ] [Set up project integrations](https://gitlab.com/service30/vnpost-postenp/-/settings/integrations)
|
||||
|
||||
## Collaborate with your team
|
||||
|
||||
- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/)
|
||||
- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html)
|
||||
- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
|
||||
- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/)
|
||||
- [ ] [Automatically merge when pipeline succeeds](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html)
|
||||
|
||||
## Test and Deploy
|
||||
|
||||
Use the built-in continuous integration in GitLab.
|
||||
|
||||
- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html)
|
||||
- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing(SAST)](https://docs.gitlab.com/ee/user/application_security/sast/)
|
||||
- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html)
|
||||
- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/)
|
||||
- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)
|
||||
|
||||
***
|
||||
|
||||
# Editing this README
|
||||
|
||||
When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thank you to [makeareadme.com](https://www.makeareadme.com/) for this template.
|
||||
|
||||
## Suggestions for a good README
|
||||
Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information.
|
||||
|
||||
## Name
|
||||
Choose a self-explaining name for your project.
|
||||
|
||||
## Description
|
||||
Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors.
|
||||
|
||||
## Badges
|
||||
On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge.
|
||||
|
||||
## Visuals
|
||||
Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method.
|
||||
|
||||
## Installation
|
||||
Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection.
|
||||
|
||||
## Usage
|
||||
Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README.
|
||||
|
||||
## Support
|
||||
Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc.
|
||||
|
||||
## Roadmap
|
||||
If you have ideas for releases in the future, it is a good idea to list them in the README.
|
||||
|
||||
## Contributing
|
||||
State if you are open to contributions and what your requirements are for accepting them.
|
||||
|
||||
For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self.
|
||||
|
||||
You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser.
|
||||
|
||||
## Authors and acknowledgment
|
||||
Show your appreciation to those who have contributed to the project.
|
||||
|
||||
## License
|
||||
For open source projects, say how it is licensed.
|
||||
|
||||
## Project status
|
||||
If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.
|
||||
146
Phaha_Package/angular.json
Normal file
146
Phaha_Package/angular.json
Normal file
@ -0,0 +1,146 @@
|
||||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"customer": {
|
||||
"projectType": "application",
|
||||
"schematics": {
|
||||
"@schematics/angular:component": {
|
||||
"style": "scss"
|
||||
}
|
||||
},
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
"prefix": "app",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"outputPath": "dist/customer",
|
||||
"index": "src/index.html",
|
||||
"main": "src/main.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"inlineStyleLanguage": "scss",
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets",
|
||||
"src/firebase-messaging-sw.js",
|
||||
"src/manifest.json",
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "node_modules/ngx-extended-pdf-viewer/assets/",
|
||||
"output": "/assets/"
|
||||
}
|
||||
],
|
||||
"styles": [
|
||||
"src/styles.scss",
|
||||
"node_modules/bootstrap/dist/css/bootstrap.css",
|
||||
"node_modules/ngx-toastr/toastr.css",
|
||||
"node_modules/flatpickr/dist/flatpickr.min.css",
|
||||
"./node_modules/quill/dist/quill.snow.css",
|
||||
"./node_modules/quill/dist/quill.core.css"
|
||||
],
|
||||
"scripts": [
|
||||
"node_modules/bootstrap/dist/js/bootstrap.js",
|
||||
"./node_modules/quill/dist/quill.min.js"
|
||||
]
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"optimization": {
|
||||
"scripts": true,
|
||||
"styles": {
|
||||
"minify": true,
|
||||
"inlineCritical": false
|
||||
},
|
||||
"fonts": true
|
||||
},
|
||||
"sourceMap": false,
|
||||
"namedChunks": false,
|
||||
"aot": true,
|
||||
"extractLicenses": true,
|
||||
"vendorChunk": false,
|
||||
"buildOptimizer": true,
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "4mb",
|
||||
"maximumError": "5mb"
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
"maximumWarning": "150kb",
|
||||
"maximumError": "150kb"
|
||||
}
|
||||
],
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"outputHashing": "all"
|
||||
},
|
||||
"development": {
|
||||
"buildOptimizer": false,
|
||||
"optimization": false,
|
||||
"vendorChunk": true,
|
||||
"extractLicenses": false,
|
||||
"sourceMap": true,
|
||||
"namedChunks": true
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "customer:build:production"
|
||||
},
|
||||
"development": {
|
||||
"browserTarget": "customer:build:development"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "development"
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
"options": {
|
||||
"browserTarget": "customer:build"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "src/test.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "tsconfig.spec.json",
|
||||
"karmaConfig": "karma.conf.js",
|
||||
"inlineStyleLanguage": "scss",
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets",
|
||||
"src/firebase-messaging-sw.js",
|
||||
"src/manifest.json",
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "node_modules/ngx-extended-pdf-viewer/assets/",
|
||||
"output": "/assets/"
|
||||
}
|
||||
],
|
||||
"styles": [
|
||||
"src/styles.scss"
|
||||
],
|
||||
"scripts": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"cli": {
|
||||
"analytics": "a9c3b5ff-118e-4409-a8fb-d930b33735ca"
|
||||
}
|
||||
}
|
||||
44
Phaha_Package/karma.conf.js
Normal file
44
Phaha_Package/karma.conf.js
Normal file
@ -0,0 +1,44 @@
|
||||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage'),
|
||||
require('@angular-devkit/build-angular/plugins/karma')
|
||||
],
|
||||
client: {
|
||||
jasmine: {
|
||||
// you can add configuration options for Jasmine here
|
||||
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
|
||||
// for example, you can disable the random execution with `random: false`
|
||||
// or set a specific seed with `seed: 4321`
|
||||
},
|
||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
jasmineHtmlReporter: {
|
||||
suppressAll: true // removes the duplicated traces
|
||||
},
|
||||
coverageReporter: {
|
||||
dir: require('path').join(__dirname, './coverage/customer'),
|
||||
subdir: '.',
|
||||
reporters: [
|
||||
{ type: 'html' },
|
||||
{ type: 'text-summary' }
|
||||
]
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false,
|
||||
restartOnFileChange: true
|
||||
});
|
||||
};
|
||||
82
Phaha_Package/package.json
Normal file
82
Phaha_Package/package.json
Normal file
@ -0,0 +1,82 @@
|
||||
{
|
||||
"name": "customer",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"watch": "ng build --watch --configuration development",
|
||||
"test": "ng test",
|
||||
"build": "node --max_old_space_size=6144 ./node_modules/@angular/cli/bin/ng build --configuration production --build-optimizer",
|
||||
"build-stats": "node --max_old_space_size=6144 ./node_modules/@angular/cli/bin/ng build --stats-json",
|
||||
"build:prod": "node --max_old_space_size=6144 ./node_modules/@angular/cli/bin/ng build --configuration production",
|
||||
"build:prod-stats": "node --max_old_space_size=6144 ./node_modules/@angular/cli/bin/ng build --configuration production --stats-json",
|
||||
"bundle-analyzer": "webpack-bundle-analyzer dist/sml-vcu/stats.json"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "^14.0.5",
|
||||
"@angular/cdk": "^14.2.1",
|
||||
"@angular/common": "^14.0.0",
|
||||
"@angular/compiler": "^14.0.0",
|
||||
"@angular/core": "^14.0.0",
|
||||
"@angular/fire": "^7.4.1",
|
||||
"@angular/forms": "^14.0.0",
|
||||
"@angular/localize": "^14.0.3",
|
||||
"@angular/platform-browser": "^14.0.0",
|
||||
"@angular/platform-browser-dynamic": "^14.0.0",
|
||||
"@angular/router": "^14.0.0",
|
||||
"@fortawesome/angular-fontawesome": "^0.11.1",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.2.0",
|
||||
"@fortawesome/free-brands-svg-icons": "^6.2.0",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.2.0",
|
||||
"@icon/unicons": "^3.0.6-alpha.0",
|
||||
"@ng-bootstrap/ng-bootstrap": "^12.1.2",
|
||||
"@ng-select/ng-select": "^9.0.2",
|
||||
"@ngx-translate/core": "^14.0.0",
|
||||
"@ngx-translate/http-loader": "^7.0.0",
|
||||
"@popperjs/core": "^2.11.5",
|
||||
"@types/file-saver": "^2.0.5",
|
||||
"@types/popper.js": "^1.11.0",
|
||||
"@types/quill": "1.3.10",
|
||||
"angular-snapscroll": "^1.3.1",
|
||||
"bootstrap": "^5.1.3",
|
||||
"bootstrap-icons": "^1.8.3",
|
||||
"file-saver": "^2.0.5",
|
||||
"firebase": "9.8.4",
|
||||
"flatpickr": "^4.6.13",
|
||||
"hammerjs": "^2.0.8",
|
||||
"js-sha256": "^0.9.0",
|
||||
"moment": "^2.29.4",
|
||||
"ng-block-ui": "^3.0.2",
|
||||
"ng2-flatpickr": "^9.0.0",
|
||||
"ng2-pdf-viewer": "^9.1.2",
|
||||
"ngx-device-detector": "^4.0.1",
|
||||
"ngx-extended-pdf-viewer": "^14.0.6",
|
||||
"ngx-loading": "^13.0.1",
|
||||
"ngx-plyr": "4.0.0",
|
||||
"ngx-quill": "^18.0.0",
|
||||
"ngx-sharebuttons": "^11.0.0",
|
||||
"ngx-toastr": "^15.0.0",
|
||||
"plyr": "3.6.4",
|
||||
"quill": "^1.3.7",
|
||||
"rxjs": "~7.5.0",
|
||||
"sweetalert2": "^11.4.24",
|
||||
"swiper": "^8.2.6",
|
||||
"tslib": "^2.3.0",
|
||||
"zone.js": "~0.11.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "^14.0.2",
|
||||
"@angular/cli": "~14.0.2",
|
||||
"@angular/compiler-cli": "^14.0.0",
|
||||
"@types/hammerjs": "^2.0.41",
|
||||
"@types/jasmine": "~4.0.0",
|
||||
"jasmine-core": "~4.1.0",
|
||||
"karma": "~6.3.0",
|
||||
"karma-chrome-launcher": "~3.1.0",
|
||||
"karma-coverage": "~2.2.0",
|
||||
"karma-jasmine": "~5.0.0",
|
||||
"karma-jasmine-html-reporter": "~1.7.0",
|
||||
"typescript": "~4.7.2"
|
||||
}
|
||||
}
|
||||
16
Phaha_Package/src/app/Models/model.ts
Normal file
16
Phaha_Package/src/app/Models/model.ts
Normal file
@ -0,0 +1,16 @@
|
||||
export class PageModel {
|
||||
page: number = 1;
|
||||
pageSize: number = 10;
|
||||
keyWord: string = "";
|
||||
sortColumn?: string;
|
||||
sortDirection?: SortDirection;
|
||||
totalRecords: number = 0;
|
||||
firstItemOnPage: number = 0;
|
||||
result: any = [];
|
||||
editorialOfficeId: any = null;
|
||||
pageNumber: number = 1;
|
||||
totalItemCount: number = 0;
|
||||
pageCount: number = 0;
|
||||
}
|
||||
|
||||
export type SortDirection = 'asc' | 'desc' | '';
|
||||
116
Phaha_Package/src/app/app-routing.ts
Normal file
116
Phaha_Package/src/app/app-routing.ts
Normal file
@ -0,0 +1,116 @@
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { PackageDetailComponent } from './package/package-detail/package-detail.component';
|
||||
import { PackageHistoryComponent } from './package-history/package-history.component';
|
||||
import { ViewBookComponent } from "./view-book/view-book.component";
|
||||
import { LoginComponent } from './login/login.component';
|
||||
import { PackagePaymentComponent } from './package/package-payment/package-payment.component';
|
||||
import { PaymentSuccessComponent } from './package/package-payment/payment-success/payment-success.component';
|
||||
import { ForgetPasswordComponent } from './forget-password/forget-password.component';
|
||||
import { VerifyEmailComponent } from './register-user/verify-email/verify-email.component';
|
||||
import { ListPackageComponent } from "./my-package/list-package/list-package.component";
|
||||
import { AddUserComponent } from "./my-package/add-user/add-user.component";
|
||||
import { PackageTrialComponent } from './package/package-trial/package-trial.component';
|
||||
import { EditorialOfficeListComponent } from './editorial-office/editorial-office-list/editorial-office-list.component';
|
||||
import { AuthorListComponent } from './home/author-list/author-list.component';
|
||||
import { ErrorNotFoundComponent } from './layout/error-not-found/error-not-found.component';
|
||||
import { PageNewsPrfeditorialPrfauthorComponent } from './page-news-prfeditorial-prfauthor/page-news-prfeditorial-prfauthor.component';
|
||||
import { PagePrfEditorialOfficeComponent } from './page-news-prfeditorial-prfauthor/prf-editorial-office/page-prf-editorial-office/page-prf-editorial-office.component';
|
||||
import { PagePrfAuthorComponent } from './page-news-prfeditorial-prfauthor/prf-author/page-prf-author/page-prf-author.component';
|
||||
import { PageDetailPrfAuthorComponent } from './page-news-prfeditorial-prfauthor/prf-author/page-prf-author/page-detail-prf-author/page-detail-prf-author.component';
|
||||
import { PageDetailPrfEditorialOfficeComponent } from './page-news-prfeditorial-prfauthor/prf-editorial-office/page-prf-editorial-office/page-detail-prf-editorial-office/page-detail-prf-editorial-office.component';
|
||||
import { PageNewsCategoryComponent } from './page-news-prfeditorial-prfauthor/page-news/page-news-category/page-news-category.component';
|
||||
import { PageNewsDetailComponent } from './page-news-prfeditorial-prfauthor/page-news/page-news-category/page-news-detail/page-news-detail.component';
|
||||
import { BookDetailsComponent } from './book/book-details/book-details.component';
|
||||
import { BookListByCategoryComponent } from './book/book-list-by-category/book-list-by-category.component';
|
||||
import { PackageCodeComponent } from './my-package/package-code/package-code.component';
|
||||
import { HonorPressComponent } from './honor-press/honor-press.component';
|
||||
import { DetailHonorPressComponent } from './honor-press/detail-honor-press/detail-honor-press.component';
|
||||
import { ResetPasswordComponent } from "./reset-password/reset-password.component";
|
||||
import { ViewTestComponent } from './view-book/view-test/view-test.component';
|
||||
import { AskonomyDetailComponent } from './package/package-askonomy/askonomy-detail/askonomy-detail.component';
|
||||
import { AskonomyViewComponent } from './package/package-askonomy/askonomy-view/askonomy-view.component';
|
||||
import { HomeV2Component } from './template-2/home-2/home-v2.component';
|
||||
import { PackageNewsComponent } from './template-2/package-news/package-news.component';
|
||||
import { PackageNewsDetailComponent } from './template-2/package-news/package-news-detail/package-news-detail.component';
|
||||
import { VneconomyComponent } from './editorial-office/vneconomy/vneconomy-home/vneconomy.component';
|
||||
import { VneconomyProfileComponent } from './editorial-office/vneconomy/vneconomy-profile/vneconomy-profile.component';
|
||||
import { VneconomyDetailComponent } from './editorial-office/vneconomy/vneconomy-detail/vneconomy-detail.component';
|
||||
import { VneconomyPremiumComponent } from './editorial-office/vneconomy/vneconomy-premium/vneconomy-premium.component';
|
||||
import { VneconomyAskonomyComponent } from './editorial-office/vneconomy/vneconomy-askonomy/vneconomy-askonomy.component';
|
||||
import { VneconomyPackagesComponent } from './editorial-office/vneconomy/vneconomy-packages/vneconomy-packages.component';
|
||||
import { PackageUpgradeComponent } from './package/package-upgrade/package-upgrade.component';
|
||||
import { VneconomyNewpaperComponent } from './editorial-office/vneconomy/vneconomy-newpaper/vneconomy-newpaper.component';
|
||||
import { EditorialDetailComponent } from './modules/editorial/components/editorial-detail/editorial-detail.component';
|
||||
import { NewspaperDetailComponent } from './modules/newspaper/components/newspaper-detail/newspaper-detail.component';
|
||||
import { PackageSearchComponent } from './modules/packages/components/package-search/package-search.component';
|
||||
import { AccountProfileComponent } from './modules/account/components/account-profile/account-profile.component';
|
||||
import { PaymentInfoComponent } from './package/package-payment/payment-info/payment-info.component';
|
||||
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '', component: HomeV2Component },
|
||||
{ path: 'chi-tiet-goi/:id', component: PackageDetailComponent },
|
||||
// { path: 'chi-tiet-askonomy/:id', component: AskonomyDetailComponent },
|
||||
|
||||
{ path: 'tap-chi-kinh-te-viet-nam', component: VneconomyComponent, data: { showAskonomy: false } },
|
||||
{ path: 'tap-chi-kinh-te-viet-nam/so-bao', component: VneconomyNewpaperComponent, data: { showAskonomy: false } },
|
||||
{ path: 'chi-tiet-toa-soan/tap-chi-kinh-te-viet-nam', component: VneconomyComponent, data: { showAskonomy: false } },
|
||||
{ path: 'tap-chi-kinh-te-viet-nam/profile', component: VneconomyProfileComponent, data: { showAskonomy: false } },
|
||||
{ path: 'tap-chi-kinh-te-viet-nam/premium', component: VneconomyPremiumComponent, data: { showAskonomy: false } },
|
||||
{ path: 'tap-chi-kinh-te-viet-nam/askonomy', component: VneconomyAskonomyComponent, data: { showAskonomy: false } },
|
||||
{ path: 'tap-chi-kinh-te-viet-nam/packages', component: VneconomyPackagesComponent, data: { showAskonomy: false } },
|
||||
{ path: 'tap-chi-kinh-te-viet-nam/detail/:id', component: VneconomyDetailComponent, data: { showAskonomy: false } },
|
||||
|
||||
{ path: 'askonomy', component: AskonomyViewComponent, data: { showHeader: false, showFooter: false, showAskonomy: false } },
|
||||
{ path: 'user/package-history', component: PackageHistoryComponent },
|
||||
{ path: 'auth/login', component: LoginComponent },
|
||||
{ path: 'auth/login?return=', component: LoginComponent },
|
||||
{ path: 'view/:id', component: ViewBookComponent, data: { showHeader: false, showFooter: false } },
|
||||
{ path: 'view-trial/:id', component: ViewBookComponent, data: { showHeader: false, showFooter: false } },
|
||||
{ path: 'view-test/:token', component: ViewTestComponent, data: { showHeader: false, showFooter: false } },
|
||||
|
||||
{ path: 'package-upgrade/:id/:packuserid', component: PackageUpgradeComponent },
|
||||
{ path: 'package-pay/:id', component: PackagePaymentComponent },
|
||||
{ path: 'package-pay/:id/:type', component: PackagePaymentComponent },
|
||||
{ path: 'package-pay/:id/:type/:packuserid', component: PackagePaymentComponent },
|
||||
{ path: 'package-pay/success/:id', component: PaymentSuccessComponent },
|
||||
|
||||
{ path: 'list-news/:id', component: ListPackageComponent },
|
||||
{ path: 'search', component: PackageSearchComponent },
|
||||
{ path: 'search/:key', component: PackageSearchComponent },
|
||||
{ path: 'profile', component: AccountProfileComponent },
|
||||
{ path: 'forget-password', component: ForgetPasswordComponent },
|
||||
{ path: 'add-user/:id', component: AddUserComponent },
|
||||
{ path: 'web/auth/verify-email', component: VerifyEmailComponent },
|
||||
{ path: 'package-trial/:id', component: PackageTrialComponent },
|
||||
{ path: 'editorial-office', component: EditorialOfficeListComponent },
|
||||
{ path: 'tac-gia', component: AuthorListComponent },
|
||||
{ path: 'news-profile', component: PageNewsPrfeditorialPrfauthorComponent },
|
||||
{ path: 'news-by-category/:id', component: PageNewsCategoryComponent },
|
||||
{ path: 'news/detail/:id', component: PageNewsDetailComponent },
|
||||
{ path: 'profile-editorial-office', component: PagePrfEditorialOfficeComponent },
|
||||
{ path: 'profile-editorial-office/detail/:id', component: PageDetailPrfEditorialOfficeComponent },
|
||||
{ path: 'profile-author', component: PagePrfAuthorComponent },
|
||||
{ path: 'profile-author/detail/:id', component: PageDetailPrfAuthorComponent },
|
||||
{ path: 'chi-tiet-sach', component: BookDetailsComponent },
|
||||
{ path: 'the-loai/chu-de-sach', component: BookListByCategoryComponent },
|
||||
{ path: 'package-code', component: PackageCodeComponent },
|
||||
{ path: 'honor-press', component: HonorPressComponent, data: { showHeader: false, showFooter: false } },
|
||||
{ path: 'honor-press/detail/:id', component: DetailHonorPressComponent, data: { showHeader: false, showFooter: false } },
|
||||
{ path: 'reset-password/:token', component: ResetPasswordComponent },
|
||||
{ path: 'payment-info/:id', component: PaymentInfoComponent },
|
||||
|
||||
{ path: 'an-pham', component: PackageNewsComponent },
|
||||
{ path: 'an-pham/:cateId', component: PackageNewsComponent },
|
||||
{ path: 'chi-tiet/:id', component: NewspaperDetailComponent },
|
||||
{ path: ':slug', component: EditorialDetailComponent },
|
||||
|
||||
{ path: '**', component: ErrorNotFoundComponent, data: { showHeader: false, showFooter: false } }
|
||||
]
|
||||
|
||||
export const routing = RouterModule.forRoot(routes, {
|
||||
onSameUrlNavigation: 'reload',
|
||||
anchorScrolling: 'enabled',
|
||||
scrollPositionRestoration: 'enabled',
|
||||
});
|
||||
|
||||
20
Phaha_Package/src/app/app.component.html
Normal file
20
Phaha_Package/src/app/app.component.html
Normal file
@ -0,0 +1,20 @@
|
||||
<app-header *ngIf="showHeader"></app-header>
|
||||
<div [ngClass]="{'main-mobile': isMobile && showHeader}">
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
<app-footer *ngIf="showFooter"></app-footer>
|
||||
|
||||
<div *ngIf="showAskonomy && currentUser && month" class="box-chat-askonomy">
|
||||
<button class="askonomy_close" *ngIf="isShowAskonomy" (click)="isShowAskonomy = !isShowAskonomy;">
|
||||
<i class="uil uil-times-circle"></i>
|
||||
</button>
|
||||
<div *ngIf="isShowAskonomy" class="box-chat-askonomy-support">
|
||||
<span>Email: support.askonomy@vneconomy.vn</span>
|
||||
<a target="_blank" href="https://docs.google.com/forms/d/e/1FAIpQLSeZYkMiTgjlycw89Jci5EjShrBb9z6SEKbbZ9KnDbCt-bdJ9Q/viewform">Phản hồi</a>
|
||||
</div>
|
||||
<div class="askonomy_iframe" *ngIf="isShowAskonomy" [innerHTML]="pathIframe">
|
||||
</div>
|
||||
<div class="askonomy_icon" *ngIf="!isShowAskonomy" (click)="isShowAskonomy = !isShowAskonomy">
|
||||
<img src="/assets/images/icons/icon_askonomy.png">
|
||||
</div>
|
||||
</div>
|
||||
79
Phaha_Package/src/app/app.component.scss
Normal file
79
Phaha_Package/src/app/app.component.scss
Normal file
@ -0,0 +1,79 @@
|
||||
.mt-140 {
|
||||
margin-top: 140px;
|
||||
}
|
||||
|
||||
.mt-60 {
|
||||
margin-top: 60px;
|
||||
}
|
||||
|
||||
.box-chat-askonomy {
|
||||
position: fixed;
|
||||
bottom: 10px;
|
||||
left: 10px;
|
||||
z-index: 100;
|
||||
|
||||
.askonomy_iframe {
|
||||
background: #fff;
|
||||
width: 360px;
|
||||
|
||||
iframe {
|
||||
height: 500px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.askonomy_icon {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 0 5px #d12129;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
background: #d12129;
|
||||
}
|
||||
}
|
||||
|
||||
.askonomy_close {
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
right: -10px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
padding: 0;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
background: #fff;
|
||||
|
||||
i {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.box-chat-askonomy-support {
|
||||
|
||||
padding: 5px 10px;
|
||||
background: #fff;
|
||||
font-weight: 600;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
align-items: center;
|
||||
|
||||
a {
|
||||
|
||||
border: 1px solid #e09500;
|
||||
padding: 2px 5px;
|
||||
border-radius: 5px;
|
||||
text-decoration: none;
|
||||
color: #e09500;
|
||||
box-shadow: 0 0 5px #e09500;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
104
Phaha_Package/src/app/app.component.ts
Normal file
104
Phaha_Package/src/app/app.component.ts
Normal file
@ -0,0 +1,104 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { DomSanitizer, Meta, MetaDefinition, SafeHtml, Title } from '@angular/platform-browser';
|
||||
import { ActivatedRoute, Data, NavigationEnd, Router } from '@angular/router';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { DeviceDetectorService } from 'ngx-device-detector';
|
||||
import { filter, map, mergeMap, tap } from 'rxjs';
|
||||
import { AuthenticationService } from './auth/service/authentication.service';
|
||||
import { environment } from 'src/environments/environment';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
import { PackageService } from './package/package.service';
|
||||
import Swal from 'sweetalert2';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.scss']
|
||||
})
|
||||
export class AppComponent implements OnInit {
|
||||
showHeader = false;
|
||||
showFooter = false;
|
||||
isShowAskonomy = false;
|
||||
showAskonomy = false;
|
||||
isMobile: boolean = false;
|
||||
currentUser: any;
|
||||
urlAskonomy = environment.urlAskonomy;
|
||||
private i18nmyPackage: any;
|
||||
month = false;
|
||||
pathIframe: SafeHtml = '';
|
||||
|
||||
constructor(
|
||||
private readonly _router: Router,
|
||||
private readonly _activatedRoute: ActivatedRoute,
|
||||
public readonly _translate: TranslateService,
|
||||
private readonly _authenticationService: AuthenticationService,
|
||||
private readonly _toastrService: ToastrService,
|
||||
private readonly _sanitizer: DomSanitizer,
|
||||
private readonly _packageService: PackageService
|
||||
) {
|
||||
if (window.location.pathname.startsWith('/en')) {
|
||||
localStorage.setItem("lang", "en");
|
||||
window.location.href = window.location.href.replace('/en', '');
|
||||
} else if (!window.location.pathname.startsWith('/view') && window.location.pathname.startsWith('/vi')) {
|
||||
localStorage.setItem("lang", "vi");
|
||||
window.location.href = window.location.href.replace('/vi', '');
|
||||
}
|
||||
|
||||
if (!localStorage.getItem("lang"))
|
||||
localStorage.setItem("lang", "vi");
|
||||
|
||||
this.isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
||||
this._translate.addLangs(['en', 'vi']);
|
||||
const langcurrent = localStorage.getItem('lang');
|
||||
this._translate.setDefaultLang(langcurrent ?? 'vi');
|
||||
this._translate.use(langcurrent ?? 'vi');
|
||||
this.currentUser = this._authenticationService.currentUserValue;
|
||||
if (this.currentUser)
|
||||
this.getMonth();
|
||||
|
||||
this.onGetI18n();
|
||||
this.pathIframe = this._sanitizer.bypassSecurityTrustHtml(`<iframe style="width: 100%; height: 500px;" src="${this.urlAskonomy}" title="Trợ lý Thông tin Kinh tế" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>`);
|
||||
}
|
||||
|
||||
getMonth() {
|
||||
this._packageService.getMonth()
|
||||
.subscribe(res => {
|
||||
this.currentUser.month = res;
|
||||
if (this.currentUser.month > 5) this.month = true;
|
||||
localStorage.setItem('currentCustomer', JSON.stringify(this.currentUser));
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
showNotiVnaskonomy() {
|
||||
Swal.fire({
|
||||
title: this.i18nmyPackage.sweetAlert.askonomy.title,
|
||||
html: this.i18nmyPackage.sweetAlert.askonomy.html,
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: '#fcaf17',
|
||||
showConfirmButton: false,
|
||||
cancelButtonText: this.i18nmyPackage.sweetAlert.askonomy.close,
|
||||
customClass: {
|
||||
confirmButton: 'btn btn-primary',
|
||||
cancelButton: 'btn btn-danger ml-1'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onGetI18n() {
|
||||
this._translate.get('myPackage').subscribe(data => {
|
||||
this.i18nmyPackage = data;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this._router.events.subscribe(event => {
|
||||
if (event instanceof NavigationEnd) {
|
||||
this.showHeader = this._activatedRoute.firstChild?.snapshot.data['showHeader'] !== false;
|
||||
this.showFooter = this._activatedRoute.firstChild?.snapshot.data['showFooter'] !== false;
|
||||
this.showAskonomy = this._activatedRoute.firstChild?.snapshot.data['showAskonomy'] !== false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
144
Phaha_Package/src/app/app.module.ts
Normal file
144
Phaha_Package/src/app/app.module.ts
Normal file
@ -0,0 +1,144 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { AppComponent } from './app.component';
|
||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
import '@angular/localize/init'
|
||||
import { PackageModule } from "./package/package.module";
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { routing } from './app-routing';
|
||||
import { HomeModule } from './home/home.module';
|
||||
import { HeaderModule } from './layout/header/header.module';
|
||||
import { FooterModule } from './layout/footer/footer.module';
|
||||
import { EditorialOfficeModule } from './editorial-office/editorial-office.module';
|
||||
import { PackageHistoryComponent } from './package-history/package-history.component'
|
||||
import { JwtInterceptor } from "./auth/helpers/jwt.interceptor";
|
||||
import { LoginModule } from './login/login.module';
|
||||
import { BlockUIModule } from 'ng-block-ui';
|
||||
import { ToastrModule } from 'ngx-toastr';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { ErrorInterceptor } from './auth/helpers/error.interceptor';
|
||||
import { ViewBookModule } from "./view-book/view-book.module";
|
||||
import { Ng2FlatpickrModule } from 'ng2-flatpickr';
|
||||
import { MyPackageModule } from "./my-package/my-package.module";
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { NgSelectModule } from '@ng-select/ng-select';
|
||||
import { VerifyEmailComponent } from './register-user/verify-email/verify-email.component';
|
||||
import { NgxTranslateModule } from './translate/translate.module';
|
||||
import { HTTP_INTERCEPTORS, HttpClientModule, HttpClient } from "@angular/common/http";
|
||||
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
||||
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
|
||||
import { ErrorNotFoundComponent } from './layout/error-not-found/error-not-found.component';
|
||||
import { HomeBookIntroComponent } from './home-book-intro/home-book-intro.component';
|
||||
import { BookModule } from './book/book.module';
|
||||
import { PageNewsPrfeditorialPrfauthorModule } from './page-news-prfeditorial-prfauthor/page-news-prfeditorial-prfauthor.module';
|
||||
import { BookstoreComponent } from './bookstore/bookstore.component';
|
||||
import { HeaderBookstoreComponent } from './bookstore/layout-bookstore/header-bookstore/header-bookstore.component';
|
||||
import { FooterBookstoreComponent } from './bookstore/layout-bookstore/footer-bookstore/footer-bookstore.component';
|
||||
import { BookstoreModule } from './bookstore/bookstore.module';
|
||||
import { QuillModule } from 'ngx-quill';
|
||||
import { ShareButtonsModule } from 'ngx-sharebuttons/buttons';
|
||||
import { ShareIconsModule } from 'ngx-sharebuttons/icons';
|
||||
import { HonorPressModule } from './honor-press/honor-press.module';
|
||||
import { environment } from 'src/environments/environment';
|
||||
import { initializeApp } from "firebase/app";
|
||||
import { AngularFireModule } from "@angular/fire/compat";
|
||||
import { AngularFireMessagingModule } from '@angular/fire/compat/messaging';
|
||||
import { ResetPasswordComponent } from './reset-password/reset-password.component';
|
||||
import { RegisterUserModule } from './register-user/register-user.module';
|
||||
import { HomeV2Module } from './template-2/home-2/home-v2.module';
|
||||
import { PackageNewsModule } from './template-2/package-news/package-news.module';
|
||||
import { PackageNewsDetailModule } from './template-2/package-news/package-news-detail/package-news-detail.module';
|
||||
import { PackageNewsOfOfficesModule } from './template-2/package-news/package-news-of-offices/package-news-of-offices.module';
|
||||
import { VneconomyModule } from './editorial-office/vneconomy/vneconomy-home/vneconomy.module';
|
||||
import { VneconomyProfileModule } from './editorial-office/vneconomy/vneconomy-profile/vneconomy-profile.module';
|
||||
import { VneconomyDetailModule } from './editorial-office/vneconomy/vneconomy-detail/vneconomy-detail.module';
|
||||
import { VneconomyPremiumModule } from './editorial-office/vneconomy/vneconomy-premium/vneconomy-premium.module';
|
||||
import { VneconomyAskonomyModule } from './editorial-office/vneconomy/vneconomy-askonomy/vneconomy-askonomy.module';
|
||||
import { VneconomyPackagesModule } from './editorial-office/vneconomy/vneconomy-packages/vneconomy-packages.module';
|
||||
import { NewspaperModule } from './modules/newspaper/newspaper.module';
|
||||
import { EditorialModule } from './modules/editorial/editorial.module';
|
||||
import { AccountModule } from './modules/account/account.module';
|
||||
|
||||
|
||||
export function httpTranslateLoader(http: HttpClient) {
|
||||
return new TranslateHttpLoader(http, '../assets/i18n/', '.json');
|
||||
}
|
||||
|
||||
// initializeApp(environment.firebase);
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent,
|
||||
PackageHistoryComponent,
|
||||
VerifyEmailComponent,
|
||||
ErrorNotFoundComponent,
|
||||
HomeBookIntroComponent,
|
||||
BookstoreComponent,
|
||||
HeaderBookstoreComponent,
|
||||
FooterBookstoreComponent,
|
||||
ResetPasswordComponent,
|
||||
],
|
||||
exports: [],
|
||||
imports: [
|
||||
routing,
|
||||
BrowserModule,
|
||||
NgbModule,
|
||||
PackageModule,
|
||||
CommonModule,
|
||||
HonorPressModule,
|
||||
HomeModule,
|
||||
HeaderModule,
|
||||
FooterModule,
|
||||
EditorialOfficeModule,
|
||||
QuillModule.forRoot(),
|
||||
BlockUIModule.forRoot(),
|
||||
ToastrModule.forRoot({ timeOut: 2000, maxOpened: 1 }),
|
||||
BrowserAnimationsModule,
|
||||
LoginModule,
|
||||
ViewBookModule,
|
||||
Ng2FlatpickrModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
MyPackageModule,
|
||||
RegisterUserModule,
|
||||
NgSelectModule,
|
||||
NgxTranslateModule,
|
||||
PageNewsPrfeditorialPrfauthorModule,
|
||||
HttpClientModule,
|
||||
TranslateModule.forRoot({
|
||||
loader: {
|
||||
provide: TranslateLoader,
|
||||
useFactory: httpTranslateLoader,
|
||||
deps: [HttpClient]
|
||||
},
|
||||
}),
|
||||
BookModule,
|
||||
BookstoreModule,
|
||||
ShareButtonsModule.withConfig({
|
||||
debug: true,
|
||||
}),
|
||||
ShareIconsModule,
|
||||
HomeV2Module,
|
||||
PackageNewsModule,
|
||||
PackageNewsDetailModule,
|
||||
PackageNewsOfOfficesModule,
|
||||
VneconomyModule,
|
||||
VneconomyProfileModule,
|
||||
VneconomyDetailModule,
|
||||
VneconomyPremiumModule,
|
||||
VneconomyAskonomyModule,
|
||||
VneconomyPackagesModule,
|
||||
NewspaperModule,
|
||||
EditorialModule,
|
||||
AccountModule
|
||||
// AngularFireModule.initializeApp(environment.firebase),
|
||||
// AngularFireMessagingModule,
|
||||
],
|
||||
providers: [
|
||||
{ provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true },
|
||||
{ provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true },
|
||||
],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule {
|
||||
}
|
||||
39
Phaha_Package/src/app/auth/helpers/auth.guards.ts
Normal file
39
Phaha_Package/src/app/auth/helpers/auth.guards.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot} from '@angular/router';
|
||||
import {AuthenticationService} from "../service/authentication.service";
|
||||
|
||||
|
||||
@Injectable({providedIn: 'root'})
|
||||
export class AuthGuard implements CanActivate {
|
||||
/**
|
||||
*
|
||||
* @param _router Router
|
||||
* @param _authenticationService AuthenticationService
|
||||
*/
|
||||
constructor(private _router: Router, private _authenticationService: AuthenticationService) {
|
||||
}
|
||||
|
||||
// canActivate
|
||||
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||
const currentUser = this._authenticationService.currentUserValue;
|
||||
if (currentUser) {
|
||||
// check if route is restricted by role
|
||||
if (route.data['role'] && route.data['role'].indexOf(currentUser.role) === -1) {
|
||||
// role not authorised so redirect to not-authorized page
|
||||
this._router.navigate(['/login']);
|
||||
return false;
|
||||
}
|
||||
// authorised so return true
|
||||
return true;
|
||||
}
|
||||
// not logged in so redirect to login page with the return url
|
||||
this._router.navigate(['/login'], {queryParams: {returnUrl: state.url}});
|
||||
return false;
|
||||
}
|
||||
|
||||
getArraysIntersection(a1: any[], a2: string | any[]) {
|
||||
return a1.filter(function (n) {
|
||||
return a2.indexOf(n) !== -1;
|
||||
});
|
||||
}
|
||||
}
|
||||
113
Phaha_Package/src/app/auth/helpers/error.interceptor.ts
Normal file
113
Phaha_Package/src/app/auth/helpers/error.interceptor.ts
Normal file
@ -0,0 +1,113 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
|
||||
import { from, lastValueFrom, Observable, throwError } from 'rxjs';
|
||||
import { catchError } from 'rxjs/operators';
|
||||
import { AuthenticationService } from "../service/authentication.service";
|
||||
import { BlockUI, NgBlockUI } from 'ng-block-ui';
|
||||
import { ActiveToast, ToastrService } from 'ngx-toastr';
|
||||
import { LoginService } from 'src/app/login/login.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
@Injectable()
|
||||
export class ErrorInterceptor implements HttpInterceptor {
|
||||
@BlockUI() blockUI: NgBlockUI | undefined;
|
||||
toastrMessage: ActiveToast<any> | undefined;
|
||||
private toastIsVisible: boolean | undefined;
|
||||
private i18n: any;
|
||||
private isLogout: boolean = false;
|
||||
/**
|
||||
* Constructor
|
||||
* @param _router Router
|
||||
* @param _authenticationService AuthenticationService
|
||||
* @param _toastr ToastrService
|
||||
*/
|
||||
constructor(
|
||||
private _router: Router,
|
||||
private _toastr: ToastrService,
|
||||
private _translate: TranslateService
|
||||
) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
|
||||
}
|
||||
|
||||
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||
return from(this.handle(request, next));
|
||||
}
|
||||
|
||||
async handle(req: HttpRequest<any>, next: HttpHandler) {
|
||||
this.onGetI18n();
|
||||
return await lastValueFrom(next.handle(req).pipe(
|
||||
catchError(err => {
|
||||
let errorMessage = '';
|
||||
switch (err.status) {
|
||||
case 0:
|
||||
errorMessage = this.i18n.expiredSignin;
|
||||
localStorage.removeItem("currentCustomer");
|
||||
break;
|
||||
case 401:
|
||||
errorMessage = this.i18n.expiredSignin;
|
||||
localStorage.removeItem("currentCustomer");
|
||||
this._router.navigate(['/']).then(() => { window.location.reload(); });
|
||||
break;
|
||||
case 404:
|
||||
errorMessage = this.i18n.link;
|
||||
this.blockUI?.stop();
|
||||
break;
|
||||
case 500:
|
||||
if (err && err.error && err.error.message == "Tài khoản không hợp lệ") {
|
||||
errorMessage = err.error.message;
|
||||
localStorage.removeItem("currentCustomer");
|
||||
window.location.reload();
|
||||
} else if (err && err.error && err.error.message)
|
||||
errorMessage = err.error.message;
|
||||
else
|
||||
errorMessage = "Lỗi máy chủ";
|
||||
break;
|
||||
case 405:
|
||||
errorMessage = this.i18n.access;
|
||||
this.blockUI?.stop();
|
||||
break;
|
||||
case 501:
|
||||
errorMessage = this.i18n.execution;
|
||||
this.blockUI?.stop();
|
||||
break;
|
||||
case 504:
|
||||
errorMessage = this.i18n.server;
|
||||
this.blockUI?.stop();
|
||||
break;
|
||||
case 408:
|
||||
errorMessage = this.i18n.browser;
|
||||
this.blockUI?.stop();
|
||||
break;
|
||||
case 400:
|
||||
errorMessage = `${err.error.message}`;
|
||||
this.blockUI?.stop();
|
||||
break;
|
||||
}
|
||||
setTimeout(() => {
|
||||
if (errorMessage && !this.toastIsVisible) {
|
||||
this.toastrMessage = this._toastr
|
||||
.error(errorMessage, this.i18n.noti, {
|
||||
timeOut: 2000,
|
||||
});
|
||||
this.toastrMessage.onShown.subscribe(() => this.toastIsVisible = true);
|
||||
this.toastrMessage.onHidden.subscribe(() => this.toastIsVisible = false);
|
||||
}
|
||||
}, 200);
|
||||
// throwError
|
||||
const error = errorMessage || err.message || err.error && err.error.message || err.statusText;
|
||||
this.blockUI?.stop();
|
||||
return throwError(error);
|
||||
|
||||
})
|
||||
));
|
||||
}
|
||||
onGetI18n() {
|
||||
this._translate.get('error-interceptor').subscribe(data => {
|
||||
this.i18n = data;
|
||||
})
|
||||
}
|
||||
}
|
||||
60
Phaha_Package/src/app/auth/helpers/jwt.interceptor.ts
Normal file
60
Phaha_Package/src/app/auth/helpers/jwt.interceptor.ts
Normal file
@ -0,0 +1,60 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HttpResponse } from '@angular/common/http';
|
||||
import { Observable } from 'rxjs';
|
||||
import { finalize } from 'rxjs/operators';
|
||||
import { environment } from "../../../environments/environment";
|
||||
import { AuthenticationService } from "../service/authentication.service";
|
||||
import { extractHostname } from './utils';
|
||||
import { BlockUI, NgBlockUI } from 'ng-block-ui';
|
||||
import { tap } from 'rxjs/operators';
|
||||
|
||||
@Injectable()
|
||||
export class JwtInterceptor implements HttpInterceptor {
|
||||
@BlockUI() blockUI: NgBlockUI | undefined;
|
||||
/**
|
||||
*
|
||||
* @param _authenticationService AuthenticationService
|
||||
*/
|
||||
constructor(private _authenticationService: AuthenticationService) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add auth header with jwt if user is logged in and request is to api url
|
||||
* @param request HttpRequest
|
||||
* @param next HttpHandler
|
||||
*/
|
||||
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||
|
||||
let requestUrl = request.url;
|
||||
|
||||
if(!requestUrl.startsWith('/package/status-paybill/'))
|
||||
this.blockUI?.start('Đang xử lý...');
|
||||
const currentUser = this._authenticationService.currentUserValue || JSON.parse(localStorage.getItem('currentCustomer') ?? '{}');
|
||||
const isLoggedIn = currentUser && currentUser.jwtToken;
|
||||
|
||||
let langUrl = localStorage.getItem('lang');
|
||||
const requestHostName = extractHostname(requestUrl);
|
||||
if (requestHostName == '' || !requestHostName) {
|
||||
requestUrl = `${environment.apiUrl}/${langUrl}${request.url}`;
|
||||
}
|
||||
|
||||
const isApiUrl = requestUrl.startsWith(environment.apiUrl);
|
||||
|
||||
if (isLoggedIn && isApiUrl) {
|
||||
request = request.clone({
|
||||
url: requestUrl,
|
||||
setHeaders: {
|
||||
Authorization: `Bearer ${currentUser?.jwtToken}`
|
||||
}
|
||||
});
|
||||
} else {
|
||||
request = request.clone({
|
||||
url: requestUrl
|
||||
});
|
||||
}
|
||||
|
||||
return next.handle(request).pipe(finalize(() => {
|
||||
this.blockUI?.stop();
|
||||
}));
|
||||
}
|
||||
}
|
||||
15
Phaha_Package/src/app/auth/helpers/utils.ts
Normal file
15
Phaha_Package/src/app/auth/helpers/utils.ts
Normal file
@ -0,0 +1,15 @@
|
||||
export function extractHostname(url: string) {
|
||||
let hostname;
|
||||
// find & remove protocol (http, ftp, etc.) and get hostname
|
||||
|
||||
if (url.indexOf('//') > -1) {
|
||||
hostname = url.split('/')[2];
|
||||
} else {
|
||||
hostname = url.split('/')[0];
|
||||
}
|
||||
|
||||
// find & remove "?"
|
||||
hostname = hostname.split('?')[0];
|
||||
|
||||
return hostname;
|
||||
}
|
||||
25
Phaha_Package/src/app/auth/models/newsPaper.ts
Normal file
25
Phaha_Package/src/app/auth/models/newsPaper.ts
Normal file
@ -0,0 +1,25 @@
|
||||
export class DetailNewsPaperModel {
|
||||
id?: number;
|
||||
content: string = '';
|
||||
description: string = '';
|
||||
editorialName: string = '';
|
||||
image: string = '';
|
||||
price: number = 0;
|
||||
promotionPrice: number = 0;
|
||||
title: string = '';
|
||||
countCustomer: number = 0;
|
||||
discountPercent: number = 0;
|
||||
isTrial: boolean = false;
|
||||
isBought: boolean = false;
|
||||
dateCreate: string = '';
|
||||
view: number = 0;
|
||||
imageDataBase64: any = {};
|
||||
}
|
||||
|
||||
export class PageModel {
|
||||
page: number = 1;
|
||||
pageSize: number = 6;
|
||||
packageId: number = 0;
|
||||
result: any = [];
|
||||
totalRecord: number = 0;
|
||||
}
|
||||
6
Phaha_Package/src/app/auth/models/package.ts
Normal file
6
Phaha_Package/src/app/auth/models/package.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export class PageModel {
|
||||
page: number = 1;
|
||||
pageSize: number = 10;
|
||||
result: any = [];
|
||||
totalRecord: number = 0;
|
||||
}
|
||||
28
Phaha_Package/src/app/auth/models/user.ts
Normal file
28
Phaha_Package/src/app/auth/models/user.ts
Normal file
@ -0,0 +1,28 @@
|
||||
export class User {
|
||||
id?: number;
|
||||
email?: string;
|
||||
password?: string;
|
||||
firstName?: string;
|
||||
username?: string;
|
||||
fullName?: string;
|
||||
avatar?: string;
|
||||
token?: string;
|
||||
jwtToken?: string;
|
||||
image?: string;
|
||||
isAdmin?: boolean;
|
||||
isActive?: boolean;
|
||||
isEnable?: boolean;
|
||||
role: any;
|
||||
}
|
||||
export class registerUser {
|
||||
fullName: string = '';
|
||||
email: string = '';
|
||||
phone: string = '';
|
||||
address: string = '';
|
||||
gender: string = '';
|
||||
birthDay: any;
|
||||
confirmPassword: string = '';
|
||||
password: string = '';
|
||||
enterpriseSignDate: any;
|
||||
}
|
||||
|
||||
79
Phaha_Package/src/app/auth/service/authentication.service.ts
Normal file
79
Phaha_Package/src/app/auth/service/authentication.service.ts
Normal file
@ -0,0 +1,79 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {HttpClient, HttpParams} from '@angular/common/http';
|
||||
import {BehaviorSubject, Observable} from 'rxjs';
|
||||
import {map} from 'rxjs/operators';
|
||||
import {User} from "../models/user";
|
||||
|
||||
@Injectable({providedIn: 'root'})
|
||||
export class AuthenticationService {
|
||||
public currentUser: Observable<User>;
|
||||
private currentUserSubject: BehaviorSubject<User>;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param _http HttpClient
|
||||
*/
|
||||
constructor(
|
||||
private _http: HttpClient,
|
||||
) {
|
||||
// @ts-ignore
|
||||
this.currentUserSubject = new BehaviorSubject<User>(JSON.parse(localStorage.getItem('currentCustomer')));
|
||||
this.currentUser = this.currentUserSubject.asObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current user
|
||||
*/
|
||||
public get currentUserValue(): User {
|
||||
return this.currentUserSubject.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirms if user is admin
|
||||
*/
|
||||
|
||||
/**
|
||||
* User login
|
||||
*
|
||||
* @param username username
|
||||
* @param password password
|
||||
* @returns user
|
||||
*/
|
||||
loginAccount(username: string, password: string) {
|
||||
return this._http
|
||||
.post<any>(`/api-user/login`, {username, password})
|
||||
.pipe(
|
||||
map(user => {
|
||||
// login successful if there's a jwt token in the response
|
||||
if (user) {
|
||||
if (user.jwtToken) {
|
||||
// store user details and jwt token in local storage to keep user logged in between page refreshes
|
||||
localStorage.setItem('currentCustomer', JSON.stringify(user));
|
||||
// notify
|
||||
this.currentUserSubject.next(user);
|
||||
} else {
|
||||
sessionStorage.setItem('currentCustomer', JSON.stringify(user));
|
||||
}
|
||||
}
|
||||
|
||||
return user;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
forgotPassword(email: string) {
|
||||
return this._http
|
||||
.post<any>(`/user/forgot-password`, {email})
|
||||
.pipe();
|
||||
}
|
||||
|
||||
/**
|
||||
* User logout
|
||||
*
|
||||
*/
|
||||
logout() {
|
||||
localStorage.removeItem('currentCustomer');
|
||||
// @ts-ignore
|
||||
this.currentUserSubject.next(null);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
<p>book-bestsellers-item works!</p>
|
||||
@ -0,0 +1,15 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-book-bestsellers-item',
|
||||
templateUrl: './book-bestsellers-item.component.html',
|
||||
styleUrls: ['./book-bestsellers-item.component.scss']
|
||||
})
|
||||
export class BookBestsellersItemComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
<div class="bestsellers">
|
||||
<div class="title-section text-uppercase">
|
||||
<a href="#">Sách bán chạy</a>
|
||||
</div>
|
||||
<div class="book-swiper">
|
||||
<swiper
|
||||
[slidesPerView]="1" [spaceBetween]="30" [slidesPerGroup]="1"
|
||||
[loop]="false" [loopFillGroupWithBlank]="true" [pagination]="false"
|
||||
[navigation]="true" class="mySwiper"
|
||||
[breakpoints]="
|
||||
{
|
||||
'576': {
|
||||
slidesPerView: 1,
|
||||
spaceBetween: 30
|
||||
},
|
||||
'992': {
|
||||
slidesPerView: 2,
|
||||
spaceBetween: 30
|
||||
},
|
||||
'1200': {
|
||||
slidesPerView: 3,
|
||||
spaceBetween: 30
|
||||
}
|
||||
}
|
||||
"
|
||||
>
|
||||
<ng-template swiperSlide *ngFor="let item of fakeArray; let index = index">
|
||||
<div class="book-item">
|
||||
<div class="item-details">
|
||||
<div class="item-img">
|
||||
<img class="book-cover" routerLink="/chi-tiet-sach" [queryParams]="{ tab: '1'}"
|
||||
src="../../../assets/images/book/book-1.jpg" alt="">
|
||||
</div>
|
||||
<div class="item-name text-uppercase">
|
||||
<a routerLink="/chi-tiet-sach" [queryParams]="{ tab: '1'}">
|
||||
bước chậm lại giữa thế gian
|
||||
</a>
|
||||
</div>
|
||||
<div class="author-name text-capitalize">
|
||||
<a href="/">
|
||||
hae min
|
||||
</a>
|
||||
</div>
|
||||
<div class="item-prices d-flex">
|
||||
<div class="original-price">400,000đ</div>
|
||||
<div class="sale-price">320,000đ</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-add">
|
||||
<i class="bi bi-cart-plus"></i>
|
||||
giỏ hàng
|
||||
</button>
|
||||
</div>
|
||||
</ng-template>
|
||||
</swiper>
|
||||
</div>
|
||||
<div class="see-more text-center">
|
||||
<span>
|
||||
<a routerLink="/the-loai/chu-de-sach">xem tất cả</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -0,0 +1,195 @@
|
||||
@import "~swiper/css";
|
||||
@import "~swiper/css/pagination";
|
||||
@import "~swiper/css/navigation";
|
||||
|
||||
app-book-bestsellers {
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.bestsellers {
|
||||
.title-section {
|
||||
text-align: center;
|
||||
margin-bottom: 32px;
|
||||
a {
|
||||
font-size: 20px;
|
||||
color: #222;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.swiper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.swiper-slide {
|
||||
text-align: center;
|
||||
background: #fff;
|
||||
border-radius: 10px;
|
||||
box-shadow: inset rgba(10, 37, 64, 0.3) 0px -2px 6px 0px;
|
||||
|
||||
/* Center slide text vertically */
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.swiper-slide img {
|
||||
display: block;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.book-swiper {
|
||||
.swiper {
|
||||
padding: 0 60px;
|
||||
}
|
||||
|
||||
.swiper-button-prev, .swiper-button-next {
|
||||
background-position: center;
|
||||
background-color: #9a9a9a;
|
||||
border-radius: 40px;
|
||||
padding: 30px 20px;
|
||||
|
||||
&:hover {
|
||||
background: #FCAF17;
|
||||
}
|
||||
}
|
||||
|
||||
.swiper-button-prev {
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
.swiper-button-next {
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
.swiper-button-next:after, .swiper-button-prev:after {
|
||||
font-family: swiper-icons;
|
||||
font-size: 24px;
|
||||
text-transform: none !important;
|
||||
letter-spacing: 0;
|
||||
font-variant: initial;
|
||||
line-height: 1;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.swiper-button-next.swiper-button-disabled, .swiper-button-prev.swiper-button-disabled {
|
||||
opacity: .35;
|
||||
cursor: auto;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.book-item {
|
||||
padding: 30px 40px;
|
||||
width: 100%;
|
||||
|
||||
.item-details {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.item-img {
|
||||
height: 280px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
img.book-cover {
|
||||
border-radius: 0 10px 10px 0;
|
||||
box-shadow: 4px 0 4px #ccc;
|
||||
cursor: pointer;
|
||||
transition: transform 0.6s;
|
||||
&:hover {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
}
|
||||
|
||||
.item-name {
|
||||
a {
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
color: #222;
|
||||
|
||||
&:hover {
|
||||
color: #E09500;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.author-name {
|
||||
padding: 6px 0;
|
||||
a {
|
||||
color: #9a9a9a;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
|
||||
&:hover {
|
||||
color: #E09500;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item-prices {
|
||||
.original-price, .sale-price {
|
||||
font-size: 16px;
|
||||
}
|
||||
.original-price {
|
||||
text-decoration: line-through;
|
||||
margin-right: 10px;
|
||||
color: #9a9a9a;
|
||||
}
|
||||
.sale-price {
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
.btn-add {
|
||||
width: 100%;
|
||||
background-color: #ffe7b8;
|
||||
color: #e09500;
|
||||
margin-top: 24px;
|
||||
padding: 8px 0;
|
||||
text-transform: uppercase;
|
||||
font-weight: 500;
|
||||
border-radius: 24px;
|
||||
i {
|
||||
font-size: 18px;
|
||||
margin-right: 9.75px;
|
||||
}
|
||||
&:hover {
|
||||
border: 1px solid #e09500
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.see-more {
|
||||
margin-top: 48px;
|
||||
|
||||
a {
|
||||
padding: 14px 24px;
|
||||
background-color: #222;
|
||||
border-radius: 6px;
|
||||
color: #fff !important;
|
||||
text-transform: uppercase;
|
||||
font-weight: 600;
|
||||
font-size: 12px;
|
||||
|
||||
&:hover {
|
||||
background-color: #E09500;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-book-bestsellers',
|
||||
templateUrl: './book-bestsellers.component.html',
|
||||
styleUrls: ['./book-bestsellers.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class BookBestsellersComponent implements OnInit {
|
||||
fakeArray = new Array(10);
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { SwiperModule } from 'swiper/angular';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
|
||||
@NgModule({
|
||||
declarations: [],
|
||||
imports: [
|
||||
CommonModule,
|
||||
SwiperModule,
|
||||
BrowserModule
|
||||
]
|
||||
})
|
||||
export class BookBestsellersModule { }
|
||||
@ -0,0 +1 @@
|
||||
<p>book-cart works!</p>
|
||||
@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { BookCartComponent } from './book-cart.component';
|
||||
|
||||
describe('BookCartComponent', () => {
|
||||
let component: BookCartComponent;
|
||||
let fixture: ComponentFixture<BookCartComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ BookCartComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(BookCartComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
15
Phaha_Package/src/app/book/book-cart/book-cart.component.ts
Normal file
15
Phaha_Package/src/app/book/book-cart/book-cart.component.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-book-cart',
|
||||
templateUrl: './book-cart.component.html',
|
||||
styleUrls: ['./book-cart.component.scss']
|
||||
})
|
||||
export class BookCartComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
<p>book-checkout works!</p>
|
||||
@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { BookCheckoutComponent } from './book-checkout.component';
|
||||
|
||||
describe('BookCheckoutComponent', () => {
|
||||
let component: BookCheckoutComponent;
|
||||
let fixture: ComponentFixture<BookCheckoutComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ BookCheckoutComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(BookCheckoutComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,15 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-book-checkout',
|
||||
templateUrl: './book-checkout.component.html',
|
||||
styleUrls: ['./book-checkout.component.scss']
|
||||
})
|
||||
export class BookCheckoutComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,225 @@
|
||||
<block-ui>
|
||||
<div class="container py-4">
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a routerLink="/">{{'breadcrumb.home' | translate}}</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Chi tiết sách</li>
|
||||
</ol>
|
||||
</nav>
|
||||
<div class="book-details">
|
||||
<div class="content-body">
|
||||
<div class="book-title">
|
||||
Bước chậm lại giữa thế gian vội
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-12">
|
||||
<div class="book-cover">
|
||||
<div class="book-cover-swiper">
|
||||
<swiper
|
||||
[slidesPerView]="1" [spaceBetween]="0" [slidesPerGroup]="1"
|
||||
[loop]="false" [loopFillGroupWithBlank]="true" [pagination]="false"
|
||||
[navigation]="true" class="mySwiper"
|
||||
[breakpoints]="
|
||||
{
|
||||
'640': {
|
||||
slidesPerView: 1,
|
||||
spaceBetween: 0
|
||||
},
|
||||
'768': {
|
||||
slidesPerView: 1,
|
||||
spaceBetween: 0
|
||||
},
|
||||
'1024': {
|
||||
slidesPerView: 1,
|
||||
spaceBetween: 0
|
||||
}
|
||||
}
|
||||
"
|
||||
>
|
||||
<ng-template swiperSlide *ngFor="let item of fakeArray; let index = index">
|
||||
<div class="book-item">
|
||||
<div class="item-details">
|
||||
<div class="item-img">
|
||||
<img class="book-cover" src="../../../assets/images/book/book-1.jpg" alt="">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</swiper>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 col-md-12">
|
||||
<div class="book-info">
|
||||
<div class="row">
|
||||
<div class="col-lg-4">
|
||||
<div class="info-title">Giá tiền</div>
|
||||
<div class="prices">
|
||||
<div class="sale">98,000đ</div>
|
||||
<div class="origin">126,000đ</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-5">
|
||||
<div class="info-title">Tác giả</div>
|
||||
<div class="author">
|
||||
<a href="/">hae min</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-3">
|
||||
<div class="info-title">Tình trạng</div>
|
||||
<div class="status">Còn hàng</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="quantity my-5">
|
||||
<div class="info-title">Số lượng</div>
|
||||
<div class="form-check-group">
|
||||
<div class="form-check-inline">
|
||||
<button class="btn btn-quantity" (click)="minus()"><i class="fa fa-minus"></i></button>
|
||||
</div>
|
||||
<div class="form-check-inline">
|
||||
<input type="text" class="number-count form-control" [(ngModel)]="inputnumber">
|
||||
</div>
|
||||
<div class="form-check-inline">
|
||||
<button class="btn btn-quantity" (click)="plus()"><i class="fa fa-plus"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-5 row">
|
||||
<div class="btn-buy-group col-lg-6 col-md-12">
|
||||
<button class="btn btn-buy">Mua ngay</button>
|
||||
</div>
|
||||
<div class="btn-buy-group col-lg-6 col-md-12">
|
||||
<button class="btn btn-add">Thêm vào giỏ hàng</button>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="book-details">
|
||||
<div class="content-body">
|
||||
<ul [(activeId)]="activeTab" ngbNav #nav="ngbNav" class="nav-pills" (navChange)="onChangeTab($event)">
|
||||
<li [ngbNavItem]="1">
|
||||
<a ngbNavLink>Chi tiết sách</a>
|
||||
<ng-template ngbNavContent>
|
||||
<div class="row">
|
||||
<div class="col-md-4 col-sm-12">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th class="table-title">Mã hàng</th>
|
||||
<th>8935235217737</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="table-title">Tên nhà cung cấp</th>
|
||||
<th>
|
||||
<a href="">
|
||||
Nhã Nam
|
||||
</a>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="table-title">Tác giả</th>
|
||||
<th>
|
||||
<a href="">
|
||||
Hae Min
|
||||
</a>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="table-title">Người dịch</th>
|
||||
<th>Nguyễn Việt Tú Anh</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="table-title">Nhà xuất bản</th>
|
||||
<th>
|
||||
<a href="">
|
||||
NXB Hội Nhà Văn
|
||||
</a>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="table-title">Năm xuất bản</th>
|
||||
<th>2018</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="table-title">Ngôn ngữ</th>
|
||||
<th>Tiếng Việt</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="table-title">Kích thước</th>
|
||||
<th>14 x 20.5 (cm)</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="table-title">Số trang</th>
|
||||
<th>254</th>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-md-8 col-sm-12">
|
||||
<div class="book-description">
|
||||
<div class="description-title">Nội dung</div>
|
||||
<div class="description-content">
|
||||
Chen vai thích cánh để có một chỗ bám trên xe buýt giờ đi làm,
|
||||
nhích từng xentimét bánh xe trên đường lúc tan sở,
|
||||
quay cuồng với thi cử và tiến độ công việc,
|
||||
lu bù vướng mắc trong những mối quan hệ cả thân lẫn sơ…
|
||||
bạn có luôn cảm thấy thế gian xung quanh mình đang xoay chuyển quá vội vàng?<br>
|
||||
Nếu có thể, hãy tạm dừng một bước.<br>
|
||||
Để tự hỏi, là do thế gian này vội vàng hay do chính tâm trí bạn đang quá bận rộn?
|
||||
Để cầm cuốn sách nhỏ dung dị mà lắng đọng này lên, chậm rãi lật giở từng trang,
|
||||
thong thả khám phá những điều mà chỉ khi bước chậm lại mới có thể thấu rõ: về các mối quan hệ,
|
||||
về chính bản thân mình, về những trăn trở trước cuộc đời và nhân thế,
|
||||
về bao điều lý trí rất hiểu nhưng trái tim chưa cách nào nghe theo.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</ng-template>
|
||||
</li>
|
||||
<li [ngbNavItem]="2">
|
||||
<a ngbNavLink>Về tác giả</a>
|
||||
<ng-template ngbNavContent>
|
||||
<div class="row">
|
||||
<div class="col-md-2 col-sm-12">
|
||||
<div class="author-ava">
|
||||
<img src="../../../assets/images/book/author-img.jpeg" alt="">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-10 col-sm-12">
|
||||
<div class="author-intro">
|
||||
Nhà văn Hae Min là một tác giả viết sách, một diễn giả, đồng thời là chuyên gia huấn luyện cấp lãnh đạo.
|
||||
Cô được mệnh danh là “nhà đấu tranh cho người hướng nội”.
|
||||
Điều cô luôn hướng đến là giúp các tổ chức nhìn nhận đúng về người hướng nội và coi trọng họ,
|
||||
và giúp những cá nhân hướng nội tự tin đảm nhiệm vị trí lãnh đạo và các vai trò có tầm ảnh hưởng.<br>
|
||||
Cô trở nên am hiểu về người hướng nội trong thời gian làm giám đốc chương trình của
|
||||
chính phủ liên bang và chuyên gia huấn luyện trong lĩnh vực phát triển sự nghiệp.
|
||||
Cô cũng đảm nhiệm vai trò cố vấn học tập và phát triển trong các tổ chức hàng đầu như
|
||||
GE, AT&T, NASA, Turner Broadcasting, và CDC. <br>
|
||||
Quyển sách đầu tiên của cô về đề tài người hướng nội,
|
||||
“The Introverted Leader: Building on Your Quiet Strength”
|
||||
(tạm dịch “Người lãnh đạo hướng nội: Phát huy thế mạnh trầm tĩnh của bạn”),
|
||||
thu hút độc giả ở khắp nơi và được dịch ra nhiều thứ tiếng.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</li>
|
||||
<li [ngbNavItem]="3">
|
||||
<a ngbNavLink>Đánh giá & Bình luận</a>
|
||||
<ng-template ngbNavContent>
|
||||
Coming soon!
|
||||
</ng-template>
|
||||
</li>
|
||||
</ul>
|
||||
<div [ngbNavOutlet]="nav"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<app-book-related></app-book-related>
|
||||
</div>
|
||||
</block-ui>
|
||||
@ -0,0 +1,269 @@
|
||||
@import "~swiper/css";
|
||||
@import "~swiper/css/pagination";
|
||||
@import "~swiper/css/navigation";
|
||||
|
||||
app-book-details {
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.book-details {
|
||||
background-color: #fff;
|
||||
border-radius: 20px;
|
||||
margin-bottom: 32px;
|
||||
|
||||
.content-body {
|
||||
padding: 32px;
|
||||
|
||||
.book-title {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
margin-bottom: 32px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.book-cover {
|
||||
background-color: #fff5e2;
|
||||
border-radius: 20px;
|
||||
|
||||
.swiper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 100px 0;
|
||||
}
|
||||
|
||||
.swiper-slide {
|
||||
padding: 32px 0;
|
||||
/* Center slide text vertically */
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.swiper-slide img {
|
||||
display: block;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.book-cover-swiper {
|
||||
.swiper {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.swiper-button-prev, .swiper-button-next {
|
||||
background-position: center;
|
||||
background-color: #9a9a9a;
|
||||
border-radius: 40px;
|
||||
padding: 30px 20px;
|
||||
|
||||
&:hover {
|
||||
background: #FCAF17;
|
||||
}
|
||||
}
|
||||
|
||||
.swiper-button-prev {
|
||||
left: 32px;
|
||||
}
|
||||
|
||||
.swiper-button-next {
|
||||
right: 32px;
|
||||
}
|
||||
|
||||
.swiper-button-next:after, .swiper-button-prev:after {
|
||||
font-family: swiper-icons;
|
||||
font-size: 24px;
|
||||
text-transform: none !important;
|
||||
letter-spacing: 0;
|
||||
font-variant: initial;
|
||||
line-height: 1;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.swiper-button-next.swiper-button-disabled, .swiper-button-prev.swiper-button-disabled {
|
||||
opacity: .35;
|
||||
cursor: auto;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.book-item {
|
||||
|
||||
.item-details {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
img.book-cover {
|
||||
max-width: 100%;
|
||||
border-radius: 0 10px 10px 0;
|
||||
box-shadow: 4px 0 4px rgb(180, 180, 180);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.book-info {
|
||||
padding-left: 12px;
|
||||
|
||||
.info-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #9a9a9a;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.prices {
|
||||
.sale {
|
||||
font-size: 32px;
|
||||
font-weight: 600;
|
||||
color: #E09500;
|
||||
}
|
||||
.origin {
|
||||
font-size: 18px;
|
||||
text-decoration: line-through;
|
||||
color: #ccc;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
.author {
|
||||
text-transform: capitalize;
|
||||
a {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
&:hover {
|
||||
color: #E09500;
|
||||
}
|
||||
}
|
||||
}
|
||||
.status {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #28A745;
|
||||
}
|
||||
.quantity {
|
||||
.form-check-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.form-check-inline {
|
||||
margin-right: 2px;
|
||||
}
|
||||
.number-count {
|
||||
width: 52px;
|
||||
border: 1px solid #9a9a9a;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.btn-quantity {
|
||||
background-color: #9a9a9a;
|
||||
border: 1px solid #9a9a9a;
|
||||
color: #fff;
|
||||
&:hover {
|
||||
background-color: #FCAF17;
|
||||
border: 1px solid #FCAF17;
|
||||
color: #222;
|
||||
}
|
||||
}
|
||||
}
|
||||
.btn-buy-group {
|
||||
.btn-buy, .btn-add {
|
||||
width: 100%;
|
||||
padding: 14px 24px;
|
||||
font-size: 12;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.btn-buy {
|
||||
background-color: #FCAF17;
|
||||
border: 1px solid #FCAF17;
|
||||
color: #fff;
|
||||
&:hover {
|
||||
background-color: #222;
|
||||
border: 1px solid #222;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
.btn-add {
|
||||
border: 1px solid #FCAF17;
|
||||
&:hover {
|
||||
background-color: #222;
|
||||
border: 1px solid #222;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.nav-pills .nav-link.active {
|
||||
border-bottom: 2px solid #FCAF17;
|
||||
background-color: #fff;
|
||||
border-radius: 0;
|
||||
color: #E09500;
|
||||
}
|
||||
.nav-pills {
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
.nav-link {
|
||||
color: #222;
|
||||
padding: 0 24px 14px 24px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.tab-pane {
|
||||
margin-top: 14px;
|
||||
}
|
||||
table {
|
||||
// width: 40%;
|
||||
thead, tbody, tfoot, tr, td, th {
|
||||
border: none;
|
||||
font-weight: normal;
|
||||
color: #222;
|
||||
}
|
||||
.table-title {
|
||||
font-weight: 600;
|
||||
}
|
||||
a {
|
||||
color: #E09500;
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
.book-description {
|
||||
.description-title {
|
||||
font-weight: 600;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.description-content {
|
||||
text-align: justify;
|
||||
font-size: 14px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
-webkit-line-clamp: 12;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
}
|
||||
.author-ava {
|
||||
img {
|
||||
max-width: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: 10px;
|
||||
}
|
||||
}
|
||||
.author-intro {
|
||||
text-align: justify;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-book-details',
|
||||
templateUrl: './book-details.component.html',
|
||||
styleUrls: ['./book-details.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class BookDetailsComponent implements OnInit {
|
||||
fakeArray = new Array(10);
|
||||
inputnumber = 0;
|
||||
public activeTab: number = 1;
|
||||
|
||||
constructor(
|
||||
private activatedRoute: ActivatedRoute,
|
||||
private router: Router
|
||||
) {
|
||||
this.activatedRoute.queryParams.subscribe((params: any) => {
|
||||
this.activeTab = parseInt(params['tab']);
|
||||
});
|
||||
}
|
||||
|
||||
plus() {
|
||||
this.inputnumber = this.inputnumber + 1;
|
||||
}
|
||||
|
||||
minus() {
|
||||
if(this.inputnumber != 0) { this.inputnumber = this.inputnumber - 1 }
|
||||
}
|
||||
|
||||
onChangeTab($event: any) {
|
||||
this.activeTab = $event.nextId;
|
||||
this.router.navigate(
|
||||
['/chi-tiet-sach'],
|
||||
{ queryParams: { tab: this.activeTab } }
|
||||
);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [],
|
||||
imports: [
|
||||
CommonModule,
|
||||
]
|
||||
})
|
||||
export class BookDetailsModule { }
|
||||
@ -0,0 +1,3 @@
|
||||
<block-ui>
|
||||
|
||||
</block-ui>
|
||||
@ -0,0 +1,5 @@
|
||||
app-book-list-by-category {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,16 @@
|
||||
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-book-list-by-category',
|
||||
templateUrl: './book-list-by-category.component.html',
|
||||
styleUrls: ['./book-list-by-category.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class BookListByCategoryComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
@NgModule({
|
||||
declarations: [],
|
||||
imports: [
|
||||
CommonModule
|
||||
]
|
||||
})
|
||||
export class BookListByCategoryModule { }
|
||||
@ -0,0 +1 @@
|
||||
<p>book-new-arrivals-item works!</p>
|
||||
@ -0,0 +1,15 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-book-new-arrivals-item',
|
||||
templateUrl: './book-new-arrivals-item.component.html',
|
||||
styleUrls: ['./book-new-arrivals-item.component.scss']
|
||||
})
|
||||
export class BookNewArrivalsItemComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
<div class="new-arrivals">
|
||||
<div class="title-section text-uppercase">
|
||||
<a href="#">Sách mới</a>
|
||||
</div>
|
||||
<div class="book-swiper">
|
||||
<swiper
|
||||
[slidesPerView]="1" [spaceBetween]="30" [slidesPerGroup]="1"
|
||||
[loop]="false" [loopFillGroupWithBlank]="true" [pagination]="false"
|
||||
[navigation]="true" class="mySwiper"
|
||||
[breakpoints]="
|
||||
{
|
||||
'640': {
|
||||
slidesPerView: 1,
|
||||
spaceBetween: 30
|
||||
},
|
||||
'768': {
|
||||
slidesPerView: 2,
|
||||
spaceBetween: 30
|
||||
},
|
||||
'1024': {
|
||||
slidesPerView: 3,
|
||||
spaceBetween: 30
|
||||
}
|
||||
}
|
||||
"
|
||||
>
|
||||
<ng-template swiperSlide *ngFor="let item of fakeArray; let index = index">
|
||||
<div class="book-item">
|
||||
<div class="item-details">
|
||||
<div class="item-img">
|
||||
<img class="book-cover" src="../../../assets/images/book/book-2.jpeg" alt="">
|
||||
</div>
|
||||
<div class="item-name text-uppercase">
|
||||
hai số phận
|
||||
</div>
|
||||
<div class="author-name text-capitalize">
|
||||
jeffrey archer
|
||||
</div>
|
||||
<div class="item-prices d-flex">
|
||||
<div class="sale-price">180,000đ</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="group-button d-flex justify-content-evenly">
|
||||
<button type="button" class="btn btn-discover" routerLink="/chi-tiet-sach" [queryParams]="{ tab: '1'}">
|
||||
<i class="bi bi-eye"></i>
|
||||
chi tiết
|
||||
</button>
|
||||
<button type="button" class="btn btn-add">
|
||||
<i class="bi bi-cart-plus"></i>
|
||||
giỏ hàng
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</swiper>
|
||||
</div>
|
||||
<div class="see-more text-center">
|
||||
<span>
|
||||
<a href="#">xem tất cả</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -0,0 +1,197 @@
|
||||
@import "~swiper/css";
|
||||
@import "~swiper/css/pagination";
|
||||
@import "~swiper/css/navigation";
|
||||
|
||||
app-book-new-arrivals {
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.new-arrivals {
|
||||
.title-section {
|
||||
text-align: center;
|
||||
margin-bottom: 32px;
|
||||
a {
|
||||
font-size: 20px;
|
||||
color: #222;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.swiper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.swiper-slide {
|
||||
text-align: center;
|
||||
background: #fff;
|
||||
border-radius: 10px;
|
||||
box-shadow: inset rgba(10, 37, 64, 0.3) 0px -2px 6px 0px;
|
||||
|
||||
/* Center slide text vertically */
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.swiper-slide img {
|
||||
display: block;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.book-swiper {
|
||||
.swiper {
|
||||
padding: 0 60px;
|
||||
}
|
||||
|
||||
.swiper-button-prev, .swiper-button-next {
|
||||
background-position: center;
|
||||
background-color: #9a9a9a;
|
||||
border-radius: 40px;
|
||||
padding: 30px 20px;
|
||||
|
||||
&:hover {
|
||||
background: #FCAF17;
|
||||
}
|
||||
}
|
||||
|
||||
.swiper-button-prev {
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
.swiper-button-next {
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
.swiper-button-next:after, .swiper-button-prev:after {
|
||||
font-family: swiper-icons;
|
||||
font-size: 24px;
|
||||
text-transform: none !important;
|
||||
letter-spacing: 0;
|
||||
font-variant: initial;
|
||||
line-height: 1;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.swiper-button-next.swiper-button-disabled, .swiper-button-prev.swiper-button-disabled {
|
||||
opacity: .35;
|
||||
cursor: auto;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.book-item {
|
||||
padding: 30px 40px;
|
||||
width: 100%;
|
||||
|
||||
.item-details {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.item-img {
|
||||
height: 280px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
img.book-cover {
|
||||
border-radius: 0 10px 10px 0;
|
||||
box-shadow: 4px 0 4px #ccc;
|
||||
cursor: pointer;
|
||||
transition: transform 0.6s;
|
||||
&:hover {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
}
|
||||
|
||||
.item-name {
|
||||
a {
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
color: #222;
|
||||
|
||||
&:hover {
|
||||
color: #E09500;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.author-name {
|
||||
padding: 6px 0;
|
||||
a {
|
||||
color: #9a9a9a;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
|
||||
&:hover {
|
||||
color: #E09500;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item-prices {
|
||||
.original-price, .sale-price {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.original-price {
|
||||
text-decoration: line-through;
|
||||
margin-right: 10px;
|
||||
color: #9a9a9a;
|
||||
}
|
||||
.sale-price {
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-add {
|
||||
width: 100%;
|
||||
background-color: #ffe7b8;
|
||||
color: #e09500;
|
||||
margin-top: 24px;
|
||||
padding: 8px 0;
|
||||
text-transform: uppercase;
|
||||
font-weight: 500;
|
||||
border-radius: 24px;
|
||||
i {
|
||||
font-size: 18px;
|
||||
margin-right: 9.75px;
|
||||
}
|
||||
&:hover {
|
||||
border: 1px solid #e09500
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.see-more {
|
||||
margin-top: 48px;
|
||||
|
||||
a {
|
||||
padding: 14px 28px;
|
||||
background-color: #222;
|
||||
border-radius: 6px;
|
||||
color: #fff !important;
|
||||
text-transform: uppercase;
|
||||
font-weight: 600;
|
||||
font-size: 12px;
|
||||
|
||||
&:hover {
|
||||
background-color: #E09500;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-book-new-arrivals',
|
||||
templateUrl: './book-new-arrivals.component.html',
|
||||
styleUrls: ['./book-new-arrivals.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class BookNewArrivalsComponent implements OnInit {
|
||||
fakeArray = new Array(10);
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { SwiperModule } from 'swiper/angular';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
|
||||
@NgModule({
|
||||
declarations: [],
|
||||
imports: [
|
||||
CommonModule,
|
||||
SwiperModule,
|
||||
BrowserModule
|
||||
]
|
||||
})
|
||||
export class BookNewArrivalsModule { }
|
||||
@ -0,0 +1,63 @@
|
||||
<div class="book-related">
|
||||
<div class="title-section text-uppercase">
|
||||
<a href="#">Sách liên quan</a>
|
||||
</div>
|
||||
<div class="book-swiper">
|
||||
<swiper
|
||||
[slidesPerView]="1" [spaceBetween]="30" [slidesPerGroup]="1"
|
||||
[loop]="false" [loopFillGroupWithBlank]="true" [pagination]="false"
|
||||
[navigation]="true" class="mySwiper"
|
||||
[breakpoints]="
|
||||
{
|
||||
'640': {
|
||||
slidesPerView: 1,
|
||||
spaceBetween: 30
|
||||
},
|
||||
'768': {
|
||||
slidesPerView: 1,
|
||||
spaceBetween: 30
|
||||
},
|
||||
'1024': {
|
||||
slidesPerView: 3,
|
||||
spaceBetween: 30
|
||||
}
|
||||
}
|
||||
"
|
||||
>
|
||||
<ng-template swiperSlide *ngFor="let item of fakeArray; let index = index">
|
||||
<div class="book-item">
|
||||
<div class="item-details">
|
||||
<div class="item-img">
|
||||
<img class="book-cover" src="../../../assets/images/book/book-1.jpg" alt="">
|
||||
</div>
|
||||
<div class="item-name text-uppercase">
|
||||
bước chậm lại giữa thế gian
|
||||
</div>
|
||||
<div class="author-name text-capitalize">
|
||||
hae min
|
||||
</div>
|
||||
<div class="item-prices d-flex">
|
||||
<div class="original-price">400,000đ</div>
|
||||
<div class="sale-price">320,000đ</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="group-button d-flex justify-content-evenly">
|
||||
<button type="button" class="btn btn-discover" routerLink="/chi-tiet-sach" [queryParams]="{ tab: '1'}">
|
||||
<i class="bi bi-eye"></i>
|
||||
chi tiết
|
||||
</button>
|
||||
<button type="button" class="btn btn-add">
|
||||
<i class="bi bi-cart-plus"></i>
|
||||
giỏ hàng
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</swiper>
|
||||
</div>
|
||||
<div class="see-more text-center">
|
||||
<span>
|
||||
<a href="#">xem tất cả</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -0,0 +1,184 @@
|
||||
@import "~swiper/css";
|
||||
@import "~swiper/css/pagination";
|
||||
@import "~swiper/css/navigation";
|
||||
|
||||
app-book-related {
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.book-related {
|
||||
.title-section {
|
||||
margin: 120px 0 20px 0;
|
||||
text-align: center;
|
||||
a {
|
||||
font-size: 20px;
|
||||
color: #222;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.swiper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.swiper-slide {
|
||||
text-align: center;
|
||||
background: #fff;
|
||||
border-radius: 10px;
|
||||
box-shadow: inset rgba(10, 37, 64, 0.3) 0px -2px 6px 0px;
|
||||
|
||||
/* Center slide text vertically */
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.swiper-slide img {
|
||||
display: block;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.book-swiper {
|
||||
.swiper {
|
||||
padding: 0 60px;
|
||||
}
|
||||
|
||||
.swiper-button-prev, .swiper-button-next {
|
||||
background-position: center;
|
||||
background-color: #9a9a9a;
|
||||
border-radius: 40px;
|
||||
padding: 30px 20px;
|
||||
|
||||
&:hover {
|
||||
background: #FCAF17;
|
||||
}
|
||||
}
|
||||
|
||||
.swiper-button-prev {
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
.swiper-button-next {
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
.swiper-button-next:after, .swiper-button-prev:after {
|
||||
font-family: swiper-icons;
|
||||
font-size: 24px;
|
||||
text-transform: none !important;
|
||||
letter-spacing: 0;
|
||||
font-variant: initial;
|
||||
line-height: 1;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.swiper-button-next.swiper-button-disabled, .swiper-button-prev.swiper-button-disabled {
|
||||
opacity: .35;
|
||||
cursor: auto;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.book-item {
|
||||
padding: 30px 40px;
|
||||
width: 100%;
|
||||
|
||||
.item-details {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.item-img {
|
||||
height: 280px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
img.book-cover {
|
||||
border-radius: 0 10px 10px 0;
|
||||
box-shadow: 4px 0 4px #ccc;
|
||||
}
|
||||
|
||||
.item-name {
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.author-name {
|
||||
color: #9a9a9a;
|
||||
font-size: 14px;
|
||||
padding: 6px 0;
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.item-prices {
|
||||
.original-price, .sale-price {
|
||||
font-size: 16px;
|
||||
}
|
||||
.original-price {
|
||||
text-decoration: line-through;
|
||||
margin-right: 10px;
|
||||
color: #9a9a9a;
|
||||
}
|
||||
.sale-price {
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.group-button {
|
||||
margin-top: 24px;
|
||||
|
||||
.btn {
|
||||
font-size: 12px;
|
||||
background-color: #ffe7b8;
|
||||
color: #e09500;
|
||||
text-transform: uppercase;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 24px;
|
||||
padding: 6px 20px;
|
||||
|
||||
i {
|
||||
font-size: 18px;
|
||||
margin-right: 9.75px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border: 1px solid #e09500;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.see-more {
|
||||
margin: 34px 0 134px 0;
|
||||
|
||||
a {
|
||||
padding: 14px 24px;
|
||||
background-color: #222;
|
||||
border-radius: 6px;
|
||||
color: #fff;
|
||||
text-transform: uppercase;
|
||||
font-weight: 600;
|
||||
font-size: 12px;
|
||||
|
||||
&:hover {
|
||||
background-color: #E09500;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-book-related',
|
||||
templateUrl: './book-related.component.html',
|
||||
styleUrls: ['./book-related.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class BookRelatedComponent implements OnInit {
|
||||
fakeArray = new Array(10);
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { SwiperModule } from 'swiper/angular';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
|
||||
@NgModule({
|
||||
declarations: [],
|
||||
imports: [
|
||||
CommonModule,
|
||||
SwiperModule,
|
||||
BrowserModule
|
||||
]
|
||||
})
|
||||
export class BookRelatedModule { }
|
||||
@ -0,0 +1 @@
|
||||
<p>book-sale-item works!</p>
|
||||
@ -0,0 +1,15 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-book-sale-item',
|
||||
templateUrl: './book-sale-item.component.html',
|
||||
styleUrls: ['./book-sale-item.component.scss']
|
||||
})
|
||||
export class BookSaleItemComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
<p>book-sale works!</p>
|
||||
15
Phaha_Package/src/app/book/book-sale/book-sale.component.ts
Normal file
15
Phaha_Package/src/app/book/book-sale/book-sale.component.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-book-sale',
|
||||
templateUrl: './book-sale.component.html',
|
||||
styleUrls: ['./book-sale.component.scss']
|
||||
})
|
||||
export class BookSaleComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
<div class="book-subject">
|
||||
<div class="title-section text-uppercase">
|
||||
<a href="#">Thể loại</a>
|
||||
</div>
|
||||
<div class="subject-swiper">
|
||||
<swiper
|
||||
[slidesPerView]="1" [spaceBetween]="0" [slidesPerGroup]="1"
|
||||
[loop]="false" [loopFillGroupWithBlank]="true" [pagination]="false"
|
||||
[navigation]="false" class="mySwiper"
|
||||
[breakpoints]="
|
||||
{
|
||||
'640': {
|
||||
slidesPerView: 1,
|
||||
spaceBetween: 0
|
||||
},
|
||||
'768': {
|
||||
slidesPerView: 1,
|
||||
spaceBetween: 0
|
||||
},
|
||||
'1024': {
|
||||
slidesPerView: 3,
|
||||
spaceBetween: 0
|
||||
}
|
||||
}
|
||||
"
|
||||
>
|
||||
<ng-template swiperSlide *ngFor="let item of fakeArray; let index = index">
|
||||
<div class="subject-item">
|
||||
<div class="item-details">
|
||||
<div class="item-img">
|
||||
<img class="book-cover" src="../../../assets/images/book/subject-cover.png" alt="">
|
||||
</div>
|
||||
<div class="item-desc">
|
||||
<div class="item-name">tiểu thuyết</div>
|
||||
<div class="item-content">
|
||||
Tiểu thuyết thường được trình bày theo dạng tự sự và trần thuật,
|
||||
có thể tập trung vào một hoặc một vài cá nhân trong không gian và
|
||||
thời gian nghệ thuật. Ngôn ngữ chính để trình bày loại hình văn học
|
||||
này chính là ngôn ngữ văn xuôi với độ dài đáng kể.
|
||||
</div>
|
||||
</div>
|
||||
<div class="see-more text-center">
|
||||
<span>
|
||||
<a href="#">khám phá</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</swiper>
|
||||
</div>
|
||||
</div>
|
||||
@ -0,0 +1,110 @@
|
||||
@import "~swiper/css";
|
||||
@import "~swiper/css/pagination";
|
||||
@import "~swiper/css/navigation";
|
||||
|
||||
app-book-subject {
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.book-subject {
|
||||
.title-section {
|
||||
text-align: center;
|
||||
margin-bottom: 32px;
|
||||
a {
|
||||
font-size: 20px;
|
||||
color: #222;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.swiper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 100px 0;
|
||||
}
|
||||
|
||||
.swiper-slide {
|
||||
text-align: center;
|
||||
font-size: 18px;
|
||||
background: #fff;
|
||||
|
||||
/* Center slide text vertically */
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.swiper-slide img {
|
||||
display: block;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.subject-swiper {
|
||||
.swiper {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.subject-item {
|
||||
|
||||
.item-details {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
img.book-cover {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.item-desc {
|
||||
padding: 10px 40px;
|
||||
|
||||
.item-name {
|
||||
text-transform: uppercase;
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.item-content {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
-webkit-line-clamp: 3;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
color: #9a9a9a;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.see-more {
|
||||
margin: 20px 0 40px 0;
|
||||
|
||||
a {
|
||||
padding: 14px 28px;
|
||||
background-color: #222;
|
||||
border-radius: 30px;
|
||||
color: #fff !important;
|
||||
text-transform: uppercase;
|
||||
font-weight: 600;
|
||||
font-size: 12px;
|
||||
|
||||
&:hover {
|
||||
background-color: #E09500;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-book-subject',
|
||||
templateUrl: './book-subject.component.html',
|
||||
styleUrls: ['./book-subject.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class BookSubjectComponent implements OnInit {
|
||||
fakeArray = new Array(12);
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { SwiperModule } from 'swiper/angular';
|
||||
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [],
|
||||
imports: [
|
||||
CommonModule,
|
||||
SwiperModule
|
||||
]
|
||||
})
|
||||
export class BookSubjectModule { }
|
||||
65
Phaha_Package/src/app/book/book.module.ts
Normal file
65
Phaha_Package/src/app/book/book.module.ts
Normal file
@ -0,0 +1,65 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { BookSaleComponent } from './book-sale/book-sale.component';
|
||||
import { BookSaleItemComponent } from './book-sale-item/book-sale-item.component';
|
||||
import { BookBestsellersComponent } from './book-bestsellers/book-bestsellers.component';
|
||||
import { BookBestsellersItemComponent } from './book-bestsellers-item/book-bestsellers-item.component';
|
||||
import { BookNewArrivalsComponent } from './book-new-arrivals/book-new-arrivals.component';
|
||||
import { BookNewArrivalsItemComponent } from './book-new-arrivals-item/book-new-arrivals-item.component';
|
||||
import { BookRelatedComponent } from './book-related/book-related.component';
|
||||
import { BookDetailsComponent } from './book-details/book-details.component';
|
||||
import { SwiperModule } from 'swiper/angular';
|
||||
import { BookSubjectComponent } from './book-subject/book-subject.component';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { BlockUIModule } from 'ng-block-ui';
|
||||
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
||||
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { BookRelatedModule } from './book-related/book-related.module';
|
||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { BookListByCategoryComponent } from './book-list-by-category/book-list-by-category.component';
|
||||
import { BookCartComponent } from './book-cart/book-cart.component';
|
||||
import { BookCheckoutComponent } from './book-checkout/book-checkout.component';
|
||||
import { BookListByCategoryModule } from './book-list-by-category/book-list-by-category.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
BookSaleComponent,
|
||||
BookSaleItemComponent,
|
||||
BookBestsellersComponent,
|
||||
BookBestsellersItemComponent,
|
||||
BookNewArrivalsComponent,
|
||||
BookNewArrivalsItemComponent,
|
||||
BookRelatedComponent,
|
||||
BookDetailsComponent,
|
||||
BookSubjectComponent,
|
||||
BookListByCategoryComponent,
|
||||
BookCartComponent,
|
||||
BookCheckoutComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
SwiperModule,
|
||||
RouterModule,
|
||||
BlockUIModule.forRoot(),
|
||||
TranslateModule.forRoot({
|
||||
loader: {
|
||||
provide: TranslateLoader,
|
||||
useFactory: (http: HttpClient) => { return new TranslateHttpLoader(http, '../../../assets/i18n', '.json'); },
|
||||
deps: [HttpClient]
|
||||
}
|
||||
}),
|
||||
FormsModule,
|
||||
NgbModule,
|
||||
|
||||
],
|
||||
exports: [
|
||||
BookBestsellersComponent,
|
||||
BookSubjectComponent,
|
||||
BookNewArrivalsComponent,
|
||||
BookRelatedModule,
|
||||
BookListByCategoryModule
|
||||
]
|
||||
})
|
||||
export class BookModule { }
|
||||
9
Phaha_Package/src/app/book/book.service.ts
Normal file
9
Phaha_Package/src/app/book/book.service.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class BookService {
|
||||
|
||||
constructor() { }
|
||||
}
|
||||
3
Phaha_Package/src/app/bookstore/bookstore.component.html
Normal file
3
Phaha_Package/src/app/bookstore/bookstore.component.html
Normal file
@ -0,0 +1,3 @@
|
||||
<block-ui>
|
||||
<app-header-bookstore></app-header-bookstore>
|
||||
</block-ui>
|
||||
3
Phaha_Package/src/app/bookstore/bookstore.component.scss
Normal file
3
Phaha_Package/src/app/bookstore/bookstore.component.scss
Normal file
@ -0,0 +1,3 @@
|
||||
app-bookstore {
|
||||
background-color: #FCAF17;
|
||||
}
|
||||
16
Phaha_Package/src/app/bookstore/bookstore.component.ts
Normal file
16
Phaha_Package/src/app/bookstore/bookstore.component.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-bookstore',
|
||||
templateUrl: './bookstore.component.html',
|
||||
styleUrls: ['./bookstore.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class BookstoreComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
||||
12
Phaha_Package/src/app/bookstore/bookstore.module.ts
Normal file
12
Phaha_Package/src/app/bookstore/bookstore.module.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { BlockUIModule } from 'ng-block-ui';
|
||||
|
||||
@NgModule({
|
||||
declarations: [],
|
||||
imports: [
|
||||
CommonModule,
|
||||
BlockUIModule.forRoot()
|
||||
]
|
||||
})
|
||||
export class BookstoreModule { }
|
||||
9
Phaha_Package/src/app/bookstore/bookstore.service.ts
Normal file
9
Phaha_Package/src/app/bookstore/bookstore.service.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class BookstoreService {
|
||||
|
||||
constructor() { }
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
<p>footer-bookstore works!</p>
|
||||
@ -0,0 +1,15 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-footer-bookstore',
|
||||
templateUrl: './footer-bookstore.component.html',
|
||||
styleUrls: ['./footer-bookstore.component.scss']
|
||||
})
|
||||
export class FooterBookstoreComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,91 @@
|
||||
<header>
|
||||
<div class="container">
|
||||
<!-- Navbar -->
|
||||
<nav class="navbar navbar-expand-lg navbar-light"><!-- Navbar brand -->
|
||||
<a class="navbar-brand mt-2 mt-lg-0" href="#">
|
||||
<img
|
||||
src="../../../../assets/images/brand/Logo.png"
|
||||
alt="Brand Logo" height="90" loading="lazy"
|
||||
/>
|
||||
</a>
|
||||
|
||||
<!-- Toggle button -->
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse"
|
||||
data-bs-target="#navbarTogglerDemo02" aria-controls="navbarTogglerDemo02" aria-expanded="false"
|
||||
aria-label="Toggle navigation"
|
||||
>
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<!-- Collapsible wrapper -->
|
||||
<div class="collapse navbar-collapse" id="navbarTogglerDemo02">
|
||||
<!-- Left links -->
|
||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" aria-current="page" href="#">Trang chủ</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">Link</a>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
Danh mục
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="#">Action</a></li>
|
||||
<li><a class="dropdown-item" href="#">Another action</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Right elements -->
|
||||
<div class="d-flex align-items-center">
|
||||
<!-- Icon -->
|
||||
<a class="text-reset me-3" href="#">
|
||||
<i class="fas fa-shopping-cart"></i>
|
||||
</a>
|
||||
|
||||
<!-- Notifications -->
|
||||
<div class="dropdown">
|
||||
<a class="text-reset me-3 dropdown-toggle hidden-arrow" href="#" id="navbarDropdownMenuLink"
|
||||
role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="fas fa-bell"></i>
|
||||
<span class="badge rounded-pill badge-notification bg-danger">1</span>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdownMenuLink">
|
||||
<li>
|
||||
<a class="dropdown-item" href="#">Some news</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item" href="#">Another news</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item" href="#">Something else here</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<button></button>
|
||||
<!-- Avatar
|
||||
<div class="dropdown">
|
||||
<a class="dropdown-toggle d-flex align-items-center hidden-arrow" href="#"
|
||||
id="navbarDropdownMenuAvatar" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<img src="https://mdbcdn.b-cdn.net/img/new/avatars/2.webp" class="rounded-circle" height="25"
|
||||
alt="Black and White Portrait of a Man" loading="lazy" />
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdownMenuAvatar">
|
||||
<li>
|
||||
<a class="dropdown-item" href="#">My profile</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item" href="#">Settings</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item" href="#">Logout</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div> -->
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
@ -0,0 +1,8 @@
|
||||
app-header-bookstore {
|
||||
header {
|
||||
background-color: #fff;
|
||||
}
|
||||
.nav-link {
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-header-bookstore',
|
||||
templateUrl: './header-bookstore.component.html',
|
||||
styleUrls: ['./header-bookstore.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class HeaderBookstoreComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [],
|
||||
imports: [
|
||||
CommonModule
|
||||
]
|
||||
})
|
||||
export class HeaderBookstoreModule { }
|
||||
@ -0,0 +1,9 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class HeaderBookstoreService {
|
||||
|
||||
constructor() { }
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
<div class="office-item">
|
||||
<div class="item-img">
|
||||
<a routerLink="/{{item.slug}}">
|
||||
<img class="img-fluid" [src]="baseUrl + item.image" (error)="errorHandler($event)">
|
||||
</a>
|
||||
</div>
|
||||
<h3 class="item-title">
|
||||
<a routerLink="/{{item.slug}}">{{item.name}}</a>
|
||||
</h3>
|
||||
<p class="item-total">{{'home.total-package' | translate}}: {{item.total}}</p>
|
||||
<p class="item-total">{{'home.total-newpaper' | translate}}: {{item.totalNewspaper}}</p>
|
||||
<div class="group-button mt-2">
|
||||
<a routerLink="/{{item.slug}}" class="btn btn-detail">{{'cta.detail' | translate}}</a>
|
||||
</div>
|
||||
</div>
|
||||
@ -0,0 +1,68 @@
|
||||
app-editorial-office-item {
|
||||
margin-bottom: 16px;
|
||||
.office-item {
|
||||
box-shadow: 0 0 5px #efefef;
|
||||
height: 100%;
|
||||
padding: 8px;
|
||||
border-radius: 5px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
overflow: hidden;
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
box-shadow: 0 0 5px #ccc;
|
||||
}
|
||||
|
||||
.item-img {
|
||||
overflow: hidden;
|
||||
border-radius: 5px;
|
||||
min-height: 80px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: -5px;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
object-fit: cover;
|
||||
transition: transform 0.6s;
|
||||
&:hover {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item-title {
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
font-weight: 600;
|
||||
margin-bottom: 8px;
|
||||
padding-top: 18px;
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
display: block;
|
||||
&:hover {
|
||||
color: #fcaf17;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item-total {
|
||||
text-align: center;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.group-button {
|
||||
text-align: center;
|
||||
a {
|
||||
background: #fcaf17;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
import { Component, Input, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { environment } from 'src/environments/environment';
|
||||
|
||||
@Component({
|
||||
selector: 'app-editorial-office-item',
|
||||
templateUrl: './editorial-office-item.component.html',
|
||||
styleUrls: ['./editorial-office-item.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class EditorialOfficeItemComponent implements OnInit {
|
||||
@Input() item: any;
|
||||
public baseUrl = environment.apiUrl.substring(0, environment.apiUrl.length - 4);
|
||||
|
||||
constructor() { }
|
||||
|
||||
errorHandler($event: any) {
|
||||
$event.target.src = '/assets/images/background/default-image.png';
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class EditorialOfficeItemService {
|
||||
|
||||
constructor() { }
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
<block-ui>
|
||||
<div class="container pt-4">
|
||||
<div class="card">
|
||||
<div class="container-fluid">
|
||||
<div class="box-office">
|
||||
<header class="office-header">
|
||||
<span>Danh sách tòa soạn</span>
|
||||
</header>
|
||||
<div class="office-search">
|
||||
<input (keyup.enter)="onGetOffice();" type="search" [(ngModel)]="dataModel.keyWord"
|
||||
class="form-control" placeholder="{{'office-detail.placeholder-search' | translate}}" />
|
||||
<button type="button" class="btn btn-primary" (click)="onGetOffice();">
|
||||
<i class="fas fa-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-3 col-sm-6 col-xs-12 mb-4"
|
||||
*ngFor="let officeItem of dataModel.result; let index = index">
|
||||
<app-editorial-office-item [item]="officeItem"></app-editorial-office-item>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cus-page">
|
||||
<ngb-pagination [collectionSize]="dataModel.totalItemCount" [(page)]="dataModel.pageNumber"
|
||||
[maxSize]="3" [rotate]="true" [pageSize]="dataModel.pageSize"
|
||||
(pageChange)="onPageChange($event)">
|
||||
</ngb-pagination>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</block-ui>
|
||||
@ -0,0 +1,77 @@
|
||||
.card {
|
||||
border: none;
|
||||
.box-office {
|
||||
padding: 16px 0;
|
||||
}
|
||||
|
||||
.office-header {
|
||||
text-transform: uppercase;
|
||||
font-weight: 600;
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 5px;
|
||||
border-bottom: 1px solid #ccc;
|
||||
span {
|
||||
font-size: 24px;
|
||||
padding-bottom: 8px;
|
||||
color: #666;
|
||||
border-bottom: 3px solid #fcaf17;
|
||||
}
|
||||
}
|
||||
|
||||
.office-search {
|
||||
display: flex;
|
||||
margin-bottom: 20px;
|
||||
input {
|
||||
height: 40px;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
background: #efefef;
|
||||
font-size: 18px;
|
||||
color: #666;
|
||||
}
|
||||
.form-control:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
button {
|
||||
width: 50px;
|
||||
border-radius: 0;
|
||||
background: #efefef;
|
||||
border: none;
|
||||
color: #fcaf17;
|
||||
padding-top: 10px;
|
||||
border-left: 1px solid #ccc;
|
||||
&:hover {
|
||||
background: #ccc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::ng-deep .cus-page {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
li.page-item,
|
||||
li.page-item.disabled {
|
||||
a,
|
||||
.page-link {
|
||||
background-color: #e9ecef;
|
||||
border-color: #e9ecef;
|
||||
color: #222;
|
||||
}
|
||||
}
|
||||
li.page-item {
|
||||
width: 36px;
|
||||
text-align: center;
|
||||
line-height: 24px;
|
||||
margin: 0 2px;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
li.page-item.active .page-link {
|
||||
background-color: #e09500;
|
||||
border-color: #e09500;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { PageModel } from 'src/app/Models/model';
|
||||
import { EditorialOfficeListService } from './editorial-office-list.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-editorial-office-list',
|
||||
templateUrl: './editorial-office-list.component.html',
|
||||
styleUrls: ['./editorial-office-list.component.scss']
|
||||
})
|
||||
export class EditorialOfficeListComponent implements OnInit {
|
||||
dataModel: PageModel = new PageModel();
|
||||
|
||||
constructor(private _editorialOfficeListService: EditorialOfficeListService) {
|
||||
this.dataModel.pageSize = 16;
|
||||
}
|
||||
|
||||
onGetOffice() {
|
||||
this._editorialOfficeListService.onGetListOffice(this.dataModel.keyWord, this.dataModel.pageNumber, this.dataModel.pageSize)
|
||||
.subscribe(data => {
|
||||
const keyWord = this.dataModel.keyWord;
|
||||
this.dataModel = data;
|
||||
|
||||
this.dataModel.keyWord = keyWord;
|
||||
});
|
||||
}
|
||||
|
||||
onPageChange(numberPage: number): void {
|
||||
this.dataModel.pageNumber = numberPage;
|
||||
this.onGetOffice();
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.onGetOffice();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class EditorialOfficeListService {
|
||||
|
||||
constructor(private _httpClient: HttpClient) { }
|
||||
|
||||
onGetListOffice(keyWord: string, page: number, pageSize: number) {
|
||||
let params = new HttpParams();
|
||||
params = params.append('keyWord', keyWord);
|
||||
params = params.append('page', page);
|
||||
params = params.append('pageSize', pageSize);
|
||||
return this._httpClient.get<any>(`/editorial-office/list-home`, { params });
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { SwiperModule } from "swiper/angular";
|
||||
import { BrowserModule } from "@angular/platform-browser";
|
||||
import { NgbModule, NgbNavModule } from "@ng-bootstrap/ng-bootstrap";
|
||||
import { PackageModule } from "../package/package.module";
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
||||
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { EditorialOfficeItemComponent } from './editorial-office-item/editorial-office-item.component';
|
||||
import { EditorialOfficeListComponent } from './editorial-office-list/editorial-office-list.component';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { BlockUIModule } from 'ng-block-ui';
|
||||
import { QuillModule } from 'ngx-quill';
|
||||
import { PackageAskonomyModule } from '../package/package-askonomy/package-askonomy.module';
|
||||
import { MyPackageModule } from '../my-package/my-package.module';
|
||||
import { VneconomyNewpaperComponent } from './vneconomy/vneconomy-newpaper/vneconomy-newpaper.component';
|
||||
import { VneconomyModule } from './vneconomy/vneconomy-home/vneconomy.module';
|
||||
import { PackagesModule } from '../modules/packages/packages.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [EditorialOfficeItemComponent, EditorialOfficeListComponent, VneconomyNewpaperComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
SwiperModule,
|
||||
BrowserModule,
|
||||
NgbModule,
|
||||
NgbNavModule,
|
||||
PackageModule,
|
||||
PackagesModule,
|
||||
ReactiveFormsModule,
|
||||
RouterModule,
|
||||
BlockUIModule.forRoot(),
|
||||
FormsModule,
|
||||
QuillModule.forRoot(),
|
||||
TranslateModule.forRoot({
|
||||
loader: {
|
||||
provide: TranslateLoader,
|
||||
useFactory: (http: HttpClient) => { return new TranslateHttpLoader(http, '../../../assets/i18n', '.json'); },
|
||||
deps: [HttpClient]
|
||||
}
|
||||
}),
|
||||
PackageAskonomyModule,
|
||||
MyPackageModule,
|
||||
VneconomyModule
|
||||
],
|
||||
exports: [
|
||||
EditorialOfficeItemComponent
|
||||
]
|
||||
})
|
||||
export class EditorialOfficeModule {
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient, HttpParams } from "@angular/common/http";
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class EditorialOfficeService {
|
||||
|
||||
constructor(
|
||||
private _httpClient: HttpClient,
|
||||
) {
|
||||
}
|
||||
|
||||
getDetailEditorialOffice(id: number) {
|
||||
return this._httpClient.get<any>(`/editorial-office/detail/${id}`);
|
||||
}
|
||||
|
||||
getDetailEditorialOfficeBySlug(slug: string) {
|
||||
let params = new HttpParams();
|
||||
params = params.set('slug', `${slug}`);
|
||||
return this._httpClient.get<any>(`/editorial-office/detail`, { params });
|
||||
}
|
||||
|
||||
getPackageOfEditorial(page: any, id: number) {
|
||||
let params = new HttpParams();
|
||||
if (page.pageNumber) {
|
||||
params = params.append('page', `${page.pageNumber}`);
|
||||
}
|
||||
if (page.pageSize) {
|
||||
params = params.append('pageSize', `${page.pageSize}`);
|
||||
}
|
||||
return this._httpClient.get<any>(`/package/in-editorial/${id}`, { params });
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
<section id="vne-tapchi" class="container mb-3">
|
||||
<div class="vne-tapchi">
|
||||
<a class="back-home-vne" href="/tap-chi-kinh-te-viet-nam"><i class="uil uil-home"></i> {{'VNECONOMY_HOME_PAGE' | translate}}</a>
|
||||
<div class="row askonomy">
|
||||
<div class="col-lg-8 col-12 col-info">
|
||||
<!-- premium -->
|
||||
<div class="row">
|
||||
<div class="col-12 col-lg-5 text-center">
|
||||
<img src="../../../../assets/templace/vneconomy/images/askonomyif.jpg" alt=""
|
||||
class="img-fluid biabao">
|
||||
</div>
|
||||
<div class="col-12 col-lg-7 vne-boxinfo mt-3 mt-lg-0">
|
||||
<h2 class="title text-center text-lg-start">Askonomy</h2>
|
||||
<p class="sub-title">{{'VNECONOMY.ASKONOMY.SUMMARY1' | translate}}</p>
|
||||
|
||||
<p class="sub-title">{{'VNECONOMY.ASKONOMY.SUMMARY2' | translate}}</p>
|
||||
|
||||
<p class="sub-title">{{'VNECONOMY.ASKONOMY.FEATURES.TITLE' | translate}}</p>
|
||||
<ul>
|
||||
<li>{{'VNECONOMY.ASKONOMY.FEATURES.FEATURE1' | translate}}</li>
|
||||
<li>{{'VNECONOMY.ASKONOMY.FEATURES.FEATURE2' | translate}}</li>
|
||||
<li>{{'VNECONOMY.ASKONOMY.FEATURES.FEATURE3' | translate}}</li>
|
||||
<li>{{'VNECONOMY.ASKONOMY.FEATURES.FEATURE4' | translate}}</li>
|
||||
<li>{{'VNECONOMY.ASKONOMY.FEATURES.FEATURE5' | translate}}</li>
|
||||
</ul>
|
||||
|
||||
<a href="/tap-chi-kinh-te-viet-nam/premium" style="text-decoration: none; color: #fcaf17; font-size: 14px; ">
|
||||
{{'VNECONOMY.ASKONOMY.SIGN_UP_FOR_PREMIUM' | translate}}</a>
|
||||
<div class="group-button text-center text-md-start">
|
||||
<a name="register" id="register" class="btn btn-warning mt-2" href="/tap-chi-kinh-te-viet-nam/packages" role="button">
|
||||
{{'VNECONOMY.ASKONOMY.EXPLORE_NOW' | translate}}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- <div class="col-12 p-3 ms-2">
|
||||
<p class="vne-cat">Catalog</p>
|
||||
<ul class="vne-cats">
|
||||
<li><a href="#">Business</a></li>
|
||||
<li><a href="#">Finance</a></li>
|
||||
</ul>
|
||||
</div> -->
|
||||
</div>
|
||||
<!-- end premium -->
|
||||
</div>
|
||||
<div class="col-lg col-12 pe-md-0 mt-lg-0 mt-4 pt-3 pt-lg-0 col-pack vne-intro">
|
||||
<div class="ratio ratio-16x9 video">
|
||||
<iframe src="https://www.youtube.com/embed/NO8-yO7Zc90?rel=0"></iframe>
|
||||
</div>
|
||||
<div class="title">
|
||||
<span>{{'TAP_CHI_KINH_TE_VIET_NAM' | translate}}</span>
|
||||
<span>Vietnam Economic Times</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<app-vneconomy-package></app-vneconomy-package>
|
||||
<app-vneconomy-register></app-vneconomy-register>
|
||||
<app-vneconomy-news-hot></app-vneconomy-news-hot>
|
||||
<app-vneconomy-comment></app-vneconomy-comment>
|
||||
<app-vneconomy-contact></app-vneconomy-contact>
|
||||
@ -0,0 +1,76 @@
|
||||
/* ------ askonomy --------- */
|
||||
/* -------------------------- */
|
||||
|
||||
@media (min-width: 1400px) {
|
||||
.vne-tapchi .askonomy .col-info {
|
||||
max-width: 66%;
|
||||
}
|
||||
|
||||
.vne-tapchi .askonomy .vne-boxinfo h2.title {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
.vne-tapchi .askonomy .biabao {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.vne-tapchi .askonomy h2.title {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.vne-tapchi .askonomy p.sub-title {
|
||||
margin-bottom: 20px;
|
||||
line-height: 1.6em;
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
.vne-tapchi .askonomy ul {
|
||||
padding-left: 1.5rem;
|
||||
}
|
||||
|
||||
.vne-tapchi .askonomy li {
|
||||
font-size: 0.85em;
|
||||
color: #777;
|
||||
}
|
||||
|
||||
.vne-tapchi .askonomy li::marker {
|
||||
color: var(--bs-warning);
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
@media (max-width: 992px) {
|
||||
.vne-tapchi .askonomy p.sub-title {
|
||||
font-size: 1em;
|
||||
line-height: 1.3em;
|
||||
}
|
||||
|
||||
.vne-tapchi .askonomy li {
|
||||
font-size: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1400px) {
|
||||
.vne-tapchi .askonomy .vne-intro .video {
|
||||
margin-top: 50px;
|
||||
}
|
||||
}
|
||||
|
||||
.vne-tapchi {
|
||||
background: #fff;
|
||||
padding: 40px 40px 40px 40px;
|
||||
}
|
||||
|
||||
.back-home-vne {
|
||||
margin-bottom: 10px;
|
||||
color: #fcaf17;
|
||||
font-size: 18px;
|
||||
position: sticky;
|
||||
text-decoration: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
i{
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-vneconomy-askonomy',
|
||||
templateUrl: './vneconomy-askonomy.component.html',
|
||||
styleUrls: ['./vneconomy-askonomy.component.scss']
|
||||
})
|
||||
export class VneconomyAskonomyComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { VneconomyAskonomyComponent } from './vneconomy-askonomy.component';
|
||||
import { SwiperModule } from 'swiper/angular';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { BlockUIModule } from 'ng-block-ui';
|
||||
import { QuillModule } from 'ngx-quill';
|
||||
import { Ng2FlatpickrModule } from 'ng2-flatpickr';
|
||||
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { LoginModule } from 'src/app/login/login.module';
|
||||
import { VneconomyModule } from '../vneconomy-home/vneconomy.module';
|
||||
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
|
||||
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
VneconomyAskonomyComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
SwiperModule,
|
||||
BrowserModule,
|
||||
NgbModule,
|
||||
ReactiveFormsModule,
|
||||
RouterModule,
|
||||
BlockUIModule.forRoot(),
|
||||
FormsModule,
|
||||
QuillModule.forRoot(),
|
||||
Ng2FlatpickrModule,
|
||||
TranslateModule.forRoot({
|
||||
loader: {
|
||||
provide: TranslateLoader,
|
||||
useFactory: (http: HttpClient) => { return new TranslateHttpLoader(http, '../../../assets/i18n', '.json'); },
|
||||
deps: [HttpClient]
|
||||
}
|
||||
}),
|
||||
LoginModule,
|
||||
VneconomyModule
|
||||
]
|
||||
})
|
||||
export class VneconomyAskonomyModule { }
|
||||
@ -0,0 +1,9 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class VneconomyAskonomyService {
|
||||
|
||||
constructor() { }
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user