mirror of
https://github.com/Nezumi-2711/foodify-frontend.git
synced 2026-09-22 05:32:00 +00:00
Initial commit
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
+1577
File diff suppressed because it is too large
Load Diff
Generated
+5
@@ -0,0 +1,5 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
Generated
+13
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/dist" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="TsLint" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
</profile>
|
||||
</component>
|
||||
Generated
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/backend.iml" filepath="$PROJECT_DIR$/.idea/backend.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -0,0 +1,27 @@
|
||||
# MultikartBackend
|
||||
|
||||
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 9.1.1.
|
||||
|
||||
## Development server
|
||||
|
||||
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
|
||||
|
||||
## Build
|
||||
|
||||
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||
|
||||
## Running end-to-end tests
|
||||
|
||||
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
|
||||
|
||||
## Further help
|
||||
|
||||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"multikart-backend": {
|
||||
"projectType": "application",
|
||||
"schematics": {
|
||||
"@schematics/angular:component": {
|
||||
"style": "scss"
|
||||
}
|
||||
},
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
"prefix": "app",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"allowedCommonJsDependencies": [
|
||||
"mousetrap",
|
||||
"hammerjs",
|
||||
"@ks89/angular-modal-gallery",
|
||||
"hammerjs",
|
||||
"rxjs/internal/operators",
|
||||
"lodash",
|
||||
"chartist",
|
||||
"chart.js",
|
||||
"clone-deep"
|
||||
],
|
||||
"outputPath": "dist/multikart-backend",
|
||||
"index": "src/index.html",
|
||||
"main": "src/main.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets"
|
||||
],
|
||||
"styles": [
|
||||
"node_modules/bootstrap/dist/css/bootstrap.min.css",
|
||||
"src/styles.scss",
|
||||
"src/assets/scss/style.scss",
|
||||
"node_modules/font-awesome/scss/font-awesome.scss"
|
||||
],
|
||||
"scripts": [],
|
||||
"vendorChunk": true,
|
||||
"extractLicenses": false,
|
||||
"buildOptimizer": false,
|
||||
"sourceMap": true,
|
||||
"optimization": false,
|
||||
"namedChunks": true
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"optimization": true,
|
||||
"outputHashing": "all",
|
||||
"sourceMap": false,
|
||||
"namedChunks": false,
|
||||
"extractLicenses": true,
|
||||
"vendorChunk": false,
|
||||
"buildOptimizer": true,
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "2mb",
|
||||
"maximumError": "5mb"
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
"maximumWarning": "6kb",
|
||||
"maximumError": "10kb"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"options": {
|
||||
"browserTarget": "multikart-backend:build"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "multikart-backend:build:production"
|
||||
}
|
||||
}
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
"options": {
|
||||
"browserTarget": "multikart-backend: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",
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets"
|
||||
],
|
||||
"styles": [
|
||||
"src/styles.scss"
|
||||
],
|
||||
"scripts": []
|
||||
}
|
||||
},
|
||||
"e2e": {
|
||||
"builder": "@angular-devkit/build-angular:protractor",
|
||||
"options": {
|
||||
"protractorConfig": "e2e/protractor.conf.js",
|
||||
"devServerTarget": "multikart-backend:serve"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"devServerTarget": "multikart-backend:serve:production"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"cli": {
|
||||
"analytics": false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// @ts-check
|
||||
// Protractor configuration file, see link for more information
|
||||
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
||||
|
||||
const { SpecReporter } = require('jasmine-spec-reporter');
|
||||
|
||||
/**
|
||||
* @type { import("protractor").Config }
|
||||
*/
|
||||
exports.config = {
|
||||
allScriptsTimeout: 11000,
|
||||
specs: [
|
||||
'./src/**/*.e2e-spec.ts'
|
||||
],
|
||||
capabilities: {
|
||||
browserName: 'chrome'
|
||||
},
|
||||
directConnect: true,
|
||||
baseUrl: 'http://localhost:4200/',
|
||||
framework: 'jasmine',
|
||||
jasmineNodeOpts: {
|
||||
showColors: true,
|
||||
defaultTimeoutInterval: 30000,
|
||||
print: function() {}
|
||||
},
|
||||
onPrepare() {
|
||||
require('ts-node').register({
|
||||
project: require('path').join(__dirname, './tsconfig.json')
|
||||
});
|
||||
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
import { AppPage } from './app.po';
|
||||
import { browser, logging } from 'protractor';
|
||||
|
||||
describe('workspace-project App', () => {
|
||||
let page: AppPage;
|
||||
|
||||
beforeEach(() => {
|
||||
page = new AppPage();
|
||||
});
|
||||
|
||||
it('should display welcome message', () => {
|
||||
page.navigateTo();
|
||||
expect(page.getTitleText()).toEqual('multikart-backend app is running!');
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
// Assert that there are no errors emitted from the browser
|
||||
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
|
||||
expect(logs).not.toContain(jasmine.objectContaining({
|
||||
level: logging.Level.SEVERE,
|
||||
} as logging.Entry));
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
import { browser, by, element } from 'protractor';
|
||||
|
||||
export class AppPage {
|
||||
navigateTo(): Promise<unknown> {
|
||||
return browser.get(browser.baseUrl) as Promise<unknown>;
|
||||
}
|
||||
|
||||
getTitleText(): Promise<string> {
|
||||
return element(by.css('app-root .content span')).getText() as Promise<string>;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/e2e",
|
||||
"module": "commonjs",
|
||||
"target": "es2018",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"jasminewd2",
|
||||
"node"
|
||||
]
|
||||
}
|
||||
}
|
||||
+395
@@ -0,0 +1,395 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
{ # this ensures the entire script is downloaded #
|
||||
|
||||
nvm_has() {
|
||||
type "$1" > /dev/null 2>&1
|
||||
}
|
||||
|
||||
nvm_install_dir() {
|
||||
printf %s "${NVM_DIR:-"$HOME/.nvm"}"
|
||||
}
|
||||
|
||||
nvm_latest_version() {
|
||||
echo "v0.33.8"
|
||||
}
|
||||
|
||||
nvm_profile_is_bash_or_zsh() {
|
||||
local TEST_PROFILE
|
||||
TEST_PROFILE="${1-}"
|
||||
case "${TEST_PROFILE-}" in
|
||||
*"/.bashrc" | *"/.bash_profile" | *"/.zshrc")
|
||||
return
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
#
|
||||
# Outputs the location to NVM depending on:
|
||||
# * The availability of $NVM_SOURCE
|
||||
# * The method used ("script" or "git" in the script, defaults to "git")
|
||||
# NVM_SOURCE always takes precedence unless the method is "script-nvm-exec"
|
||||
#
|
||||
nvm_source() {
|
||||
local NVM_METHOD
|
||||
NVM_METHOD="$1"
|
||||
local NVM_SOURCE_URL
|
||||
NVM_SOURCE_URL="$NVM_SOURCE"
|
||||
if [ "_$NVM_METHOD" = "_script-nvm-exec" ]; then
|
||||
NVM_SOURCE_URL="https://raw.githubusercontent.com/creationix/nvm/$(nvm_latest_version)/nvm-exec"
|
||||
elif [ "_$NVM_METHOD" = "_script-nvm-bash-completion" ]; then
|
||||
NVM_SOURCE_URL="https://raw.githubusercontent.com/creationix/nvm/$(nvm_latest_version)/bash_completion"
|
||||
elif [ -z "$NVM_SOURCE_URL" ]; then
|
||||
if [ "_$NVM_METHOD" = "_script" ]; then
|
||||
NVM_SOURCE_URL="https://raw.githubusercontent.com/creationix/nvm/$(nvm_latest_version)/nvm.sh"
|
||||
elif [ "_$NVM_METHOD" = "_git" ] || [ -z "$NVM_METHOD" ]; then
|
||||
NVM_SOURCE_URL="https://github.com/creationix/nvm.git"
|
||||
else
|
||||
echo >&2 "Unexpected value \"$NVM_METHOD\" for \$NVM_METHOD"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
echo "$NVM_SOURCE_URL"
|
||||
}
|
||||
|
||||
#
|
||||
# Node.js version to install
|
||||
#
|
||||
nvm_node_version() {
|
||||
echo "$NODE_VERSION"
|
||||
}
|
||||
|
||||
nvm_download() {
|
||||
if nvm_has "curl"; then
|
||||
curl --compressed -q "$@"
|
||||
elif nvm_has "wget"; then
|
||||
# Emulate curl with wget
|
||||
ARGS=$(echo "$*" | command sed -e 's/--progress-bar /--progress=bar /' \
|
||||
-e 's/-L //' \
|
||||
-e 's/--compressed //' \
|
||||
-e 's/-I /--server-response /' \
|
||||
-e 's/-s /-q /' \
|
||||
-e 's/-o /-O /' \
|
||||
-e 's/-C - /-c /')
|
||||
# shellcheck disable=SC2086
|
||||
eval wget $ARGS
|
||||
fi
|
||||
}
|
||||
|
||||
install_nvm_from_git() {
|
||||
local INSTALL_DIR
|
||||
INSTALL_DIR="$(nvm_install_dir)"
|
||||
|
||||
if [ -d "$INSTALL_DIR/.git" ]; then
|
||||
echo "=> nvm is already installed in $INSTALL_DIR, trying to update using git"
|
||||
command printf "\r=> "
|
||||
command git --git-dir="$INSTALL_DIR"/.git --work-tree="$INSTALL_DIR" fetch origin tag "$(nvm_latest_version)" --depth=1 2> /dev/null || {
|
||||
echo >&2 "Failed to update nvm, run 'git fetch' in $INSTALL_DIR yourself."
|
||||
exit 1
|
||||
}
|
||||
else
|
||||
# Cloning to $INSTALL_DIR
|
||||
echo "=> Downloading nvm from git to '$INSTALL_DIR'"
|
||||
command printf "\r=> "
|
||||
mkdir -p "${INSTALL_DIR}"
|
||||
if [ "$(ls -A "${INSTALL_DIR}")" ]; then
|
||||
command git init "${INSTALL_DIR}" || {
|
||||
echo >&2 'Failed to initialize nvm repo. Please report this!'
|
||||
exit 2
|
||||
}
|
||||
command git --git-dir="${INSTALL_DIR}/.git" remote add origin "$(nvm_source)" 2> /dev/null \
|
||||
|| command git --git-dir="${INSTALL_DIR}/.git" remote set-url origin "$(nvm_source)" || {
|
||||
echo >&2 'Failed to add remote "origin" (or set the URL). Please report this!'
|
||||
exit 2
|
||||
}
|
||||
command git --git-dir="${INSTALL_DIR}/.git" fetch origin tag "$(nvm_latest_version)" --depth=1 || {
|
||||
echo >&2 'Failed to fetch origin with tags. Please report this!'
|
||||
exit 2
|
||||
}
|
||||
else
|
||||
command git clone "$(nvm_source)" -b "$(nvm_latest_version)" --depth=1 "${INSTALL_DIR}" || {
|
||||
echo >&2 'Failed to clone nvm repo. Please report this!'
|
||||
exit 2
|
||||
}
|
||||
fi
|
||||
fi
|
||||
command git --git-dir="$INSTALL_DIR"/.git --work-tree="$INSTALL_DIR" checkout -f --quiet "$(nvm_latest_version)"
|
||||
if [ ! -z "$(command git --git-dir="$INSTALL_DIR"/.git --work-tree="$INSTALL_DIR" show-ref refs/heads/master)" ]; then
|
||||
if command git --git-dir="$INSTALL_DIR"/.git --work-tree="$INSTALL_DIR" branch --quiet 2>/dev/null; then
|
||||
command git --git-dir="$INSTALL_DIR"/.git --work-tree="$INSTALL_DIR" branch --quiet -D master >/dev/null 2>&1
|
||||
else
|
||||
echo >&2 "Your version of git is out of date. Please update it!"
|
||||
command git --git-dir="$INSTALL_DIR"/.git --work-tree="$INSTALL_DIR" branch -D master >/dev/null 2>&1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "=> Compressing and cleaning up git repository"
|
||||
if ! command git --git-dir="$INSTALL_DIR"/.git --work-tree="$INSTALL_DIR" reflog expire --expire=now --all; then
|
||||
echo >&2 "Your version of git is out of date. Please update it!"
|
||||
fi
|
||||
if ! command git --git-dir="$INSTALL_DIR"/.git --work-tree="$INSTALL_DIR" gc --auto --aggressive --prune=now ; then
|
||||
echo >&2 "Your version of git is out of date. Please update it!"
|
||||
fi
|
||||
return
|
||||
}
|
||||
|
||||
#
|
||||
# Automatically install Node.js
|
||||
#
|
||||
nvm_install_node() {
|
||||
local NODE_VERSION_LOCAL
|
||||
NODE_VERSION_LOCAL="$(nvm_node_version)"
|
||||
|
||||
if [ -z "$NODE_VERSION_LOCAL" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "=> Installing Node.js version $NODE_VERSION_LOCAL"
|
||||
nvm install "$NODE_VERSION_LOCAL"
|
||||
local CURRENT_NVM_NODE
|
||||
|
||||
CURRENT_NVM_NODE="$(nvm_version current)"
|
||||
if [ "$(nvm_version "$NODE_VERSION_LOCAL")" == "$CURRENT_NVM_NODE" ]; then
|
||||
echo "=> Node.js version $NODE_VERSION_LOCAL has been successfully installed"
|
||||
else
|
||||
echo >&2 "Failed to install Node.js $NODE_VERSION_LOCAL"
|
||||
fi
|
||||
}
|
||||
|
||||
install_nvm_as_script() {
|
||||
local INSTALL_DIR
|
||||
INSTALL_DIR="$(nvm_install_dir)"
|
||||
local NVM_SOURCE_LOCAL
|
||||
NVM_SOURCE_LOCAL="$(nvm_source script)"
|
||||
local NVM_EXEC_SOURCE
|
||||
NVM_EXEC_SOURCE="$(nvm_source script-nvm-exec)"
|
||||
local NVM_BASH_COMPLETION_SOURCE
|
||||
NVM_BASH_COMPLETION_SOURCE="$(nvm_source script-nvm-bash-completion)"
|
||||
|
||||
# Downloading to $INSTALL_DIR
|
||||
mkdir -p "$INSTALL_DIR"
|
||||
if [ -f "$INSTALL_DIR/nvm.sh" ]; then
|
||||
echo "=> nvm is already installed in $INSTALL_DIR, trying to update the script"
|
||||
else
|
||||
echo "=> Downloading nvm as script to '$INSTALL_DIR'"
|
||||
fi
|
||||
nvm_download -s "$NVM_SOURCE_LOCAL" -o "$INSTALL_DIR/nvm.sh" || {
|
||||
echo >&2 "Failed to download '$NVM_SOURCE_LOCAL'"
|
||||
return 1
|
||||
} &
|
||||
nvm_download -s "$NVM_EXEC_SOURCE" -o "$INSTALL_DIR/nvm-exec" || {
|
||||
echo >&2 "Failed to download '$NVM_EXEC_SOURCE'"
|
||||
return 2
|
||||
} &
|
||||
nvm_download -s "$NVM_BASH_COMPLETION_SOURCE" -o "$INSTALL_DIR/bash_completion" || {
|
||||
echo >&2 "Failed to download '$NVM_BASH_COMPLETION_SOURCE'"
|
||||
return 2
|
||||
} &
|
||||
for job in $(jobs -p | sort)
|
||||
do
|
||||
wait "$job" || return $?
|
||||
done
|
||||
chmod a+x "$INSTALL_DIR/nvm-exec" || {
|
||||
echo >&2 "Failed to mark '$INSTALL_DIR/nvm-exec' as executable"
|
||||
return 3
|
||||
}
|
||||
}
|
||||
|
||||
nvm_try_profile() {
|
||||
if [ -z "${1-}" ] || [ ! -f "${1}" ]; then
|
||||
return 1
|
||||
fi
|
||||
echo "${1}"
|
||||
}
|
||||
|
||||
#
|
||||
# Detect profile file if not specified as environment variable
|
||||
# (eg: PROFILE=~/.myprofile)
|
||||
# The echo'ed path is guaranteed to be an existing file
|
||||
# Otherwise, an empty string is returned
|
||||
#
|
||||
nvm_detect_profile() {
|
||||
if [ -n "${PROFILE}" ] && [ -f "${PROFILE}" ]; then
|
||||
echo "${PROFILE}"
|
||||
return
|
||||
fi
|
||||
|
||||
local DETECTED_PROFILE
|
||||
DETECTED_PROFILE=''
|
||||
local SHELLTYPE
|
||||
SHELLTYPE="$(basename "/$SHELL")"
|
||||
|
||||
if [ "$SHELLTYPE" = "bash" ]; then
|
||||
if [ -f "$HOME/.bashrc" ]; then
|
||||
DETECTED_PROFILE="$HOME/.bashrc"
|
||||
elif [ -f "$HOME/.bash_profile" ]; then
|
||||
DETECTED_PROFILE="$HOME/.bash_profile"
|
||||
fi
|
||||
elif [ "$SHELLTYPE" = "zsh" ]; then
|
||||
DETECTED_PROFILE="$HOME/.zshrc"
|
||||
fi
|
||||
|
||||
if [ -z "$DETECTED_PROFILE" ]; then
|
||||
for EACH_PROFILE in ".profile" ".bashrc" ".bash_profile" ".zshrc"
|
||||
do
|
||||
if DETECTED_PROFILE="$(nvm_try_profile "${HOME}/${EACH_PROFILE}")"; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [ ! -z "$DETECTED_PROFILE" ]; then
|
||||
echo "$DETECTED_PROFILE"
|
||||
fi
|
||||
}
|
||||
|
||||
#
|
||||
# Check whether the user has any globally-installed npm modules in their system
|
||||
# Node, and warn them if so.
|
||||
#
|
||||
nvm_check_global_modules() {
|
||||
command -v npm >/dev/null 2>&1 || return 0
|
||||
|
||||
local NPM_VERSION
|
||||
NPM_VERSION="$(npm --version)"
|
||||
NPM_VERSION="${NPM_VERSION:--1}"
|
||||
[ "${NPM_VERSION%%[!-0-9]*}" -gt 0 ] || return 0
|
||||
|
||||
local NPM_GLOBAL_MODULES
|
||||
NPM_GLOBAL_MODULES="$(
|
||||
npm list -g --depth=0 |
|
||||
command sed -e '/ npm@/d' -e '/ (empty)$/d'
|
||||
)"
|
||||
|
||||
local MODULE_COUNT
|
||||
MODULE_COUNT="$(
|
||||
command printf %s\\n "$NPM_GLOBAL_MODULES" |
|
||||
command sed -ne '1!p' | # Remove the first line
|
||||
wc -l | tr -d ' ' # Count entries
|
||||
)"
|
||||
|
||||
if [ "${MODULE_COUNT}" != '0' ]; then
|
||||
# shellcheck disable=SC2016
|
||||
echo '=> You currently have modules installed globally with `npm`. These will no'
|
||||
# shellcheck disable=SC2016
|
||||
echo '=> longer be linked to the active version of Node when you install a new node'
|
||||
# shellcheck disable=SC2016
|
||||
echo '=> with `nvm`; and they may (depending on how you construct your `$PATH`)'
|
||||
# shellcheck disable=SC2016
|
||||
echo '=> override the binaries of modules installed with `nvm`:'
|
||||
echo
|
||||
|
||||
command printf %s\\n "$NPM_GLOBAL_MODULES"
|
||||
echo '=> If you wish to uninstall them at a later point (or re-install them under your'
|
||||
# shellcheck disable=SC2016
|
||||
echo '=> `nvm` Nodes), you can remove them from the system Node as follows:'
|
||||
echo
|
||||
echo ' $ nvm use system'
|
||||
echo ' $ npm uninstall -g a_module'
|
||||
echo
|
||||
fi
|
||||
}
|
||||
|
||||
nvm_do_install() {
|
||||
if [ -z "${METHOD}" ]; then
|
||||
# Autodetect install method
|
||||
if nvm_has git; then
|
||||
install_nvm_from_git
|
||||
elif nvm_has nvm_download; then
|
||||
install_nvm_as_script
|
||||
else
|
||||
echo >&2 'You need git, curl, or wget to install nvm'
|
||||
exit 1
|
||||
fi
|
||||
elif [ "${METHOD}" = 'git' ]; then
|
||||
if ! nvm_has git; then
|
||||
echo >&2 "You need git to install nvm"
|
||||
exit 1
|
||||
fi
|
||||
install_nvm_from_git
|
||||
elif [ "${METHOD}" = 'script' ]; then
|
||||
if ! nvm_has nvm_download; then
|
||||
echo >&2 "You need curl or wget to install nvm"
|
||||
exit 1
|
||||
fi
|
||||
install_nvm_as_script
|
||||
fi
|
||||
|
||||
echo
|
||||
|
||||
local NVM_PROFILE
|
||||
NVM_PROFILE="$(nvm_detect_profile)"
|
||||
local PROFILE_INSTALL_DIR
|
||||
PROFILE_INSTALL_DIR="$(nvm_install_dir| sed "s:^$HOME:\$HOME:")"
|
||||
|
||||
SOURCE_STR="\nexport NVM_DIR=\"${PROFILE_INSTALL_DIR}\"\n[ -s \"\$NVM_DIR/nvm.sh\" ] && \\. \"\$NVM_DIR/nvm.sh\" # This loads nvm\n"
|
||||
COMPLETION_STR="[ -s \"\$NVM_DIR/bash_completion\" ] && \\. \"\$NVM_DIR/bash_completion\" # This loads nvm bash_completion\n"
|
||||
BASH_OR_ZSH=false
|
||||
|
||||
if [ -z "${NVM_PROFILE-}" ] ; then
|
||||
local TRIED_PROFILE
|
||||
if [ -n "${PROFILE}" ]; then
|
||||
TRIED_PROFILE="${NVM_PROFILE} (as defined in \$PROFILE), "
|
||||
fi
|
||||
echo "=> Profile not found. Tried ${TRIED_PROFILE-}~/.bashrc, ~/.bash_profile, ~/.zshrc, and ~/.profile."
|
||||
echo "=> Create one of them and run this script again"
|
||||
echo " OR"
|
||||
echo "=> Append the following lines to the correct file yourself:"
|
||||
command printf "${SOURCE_STR}"
|
||||
else
|
||||
if nvm_profile_is_bash_or_zsh "${NVM_PROFILE-}"; then
|
||||
BASH_OR_ZSH=true
|
||||
fi
|
||||
if ! command grep -qc '/nvm.sh' "$NVM_PROFILE"; then
|
||||
echo "=> Appending nvm source string to $NVM_PROFILE"
|
||||
command printf "${SOURCE_STR}" >> "$NVM_PROFILE"
|
||||
else
|
||||
echo "=> nvm source string already in ${NVM_PROFILE}"
|
||||
fi
|
||||
# shellcheck disable=SC2016
|
||||
if ${BASH_OR_ZSH} && ! command grep -qc '$NVM_DIR/bash_completion' "$NVM_PROFILE"; then
|
||||
echo "=> Appending bash_completion source string to $NVM_PROFILE"
|
||||
command printf "$COMPLETION_STR" >> "$NVM_PROFILE"
|
||||
else
|
||||
echo "=> bash_completion source string already in ${NVM_PROFILE}"
|
||||
fi
|
||||
fi
|
||||
if ${BASH_OR_ZSH} && [ -z "${NVM_PROFILE-}" ] ; then
|
||||
echo "=> Please also append the following lines to the if you are using bash/zsh shell:"
|
||||
command printf "${COMPLETION_STR}"
|
||||
fi
|
||||
|
||||
# Source nvm
|
||||
# shellcheck source=/dev/null
|
||||
\. "$(nvm_install_dir)/nvm.sh"
|
||||
|
||||
nvm_check_global_modules
|
||||
|
||||
nvm_install_node
|
||||
|
||||
nvm_reset
|
||||
|
||||
echo "=> Close and reopen your terminal to start using nvm or run the following to use it now:"
|
||||
command printf "${SOURCE_STR}"
|
||||
if ${BASH_OR_ZSH} ; then
|
||||
command printf "${COMPLETION_STR}"
|
||||
fi
|
||||
}
|
||||
|
||||
#
|
||||
# Unsets the various functions defined
|
||||
# during the execution of the install script
|
||||
#
|
||||
nvm_reset() {
|
||||
unset -f nvm_has nvm_install_dir nvm_latest_version nvm_profile_is_bash_or_zsh \
|
||||
nvm_source nvm_node_version nvm_download install_nvm_from_git nvm_install_node \
|
||||
install_nvm_as_script nvm_try_profile nvm_detect_profile nvm_check_global_modules \
|
||||
nvm_do_install nvm_reset
|
||||
}
|
||||
|
||||
[ "_$NVM_ENV" = "_testing" ] || nvm_do_install
|
||||
|
||||
} # this ensures the entire script is downloaded #
|
||||
@@ -0,0 +1,32 @@
|
||||
// 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-istanbul-reporter'),
|
||||
require('@angular-devkit/build-angular/plugins/karma')
|
||||
],
|
||||
client: {
|
||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
coverageIstanbulReporter: {
|
||||
dir: require('path').join(__dirname, './coverage/multikart-backend'),
|
||||
reports: ['html', 'lcovonly', 'text-summary'],
|
||||
fixWebpackSourcePaths: true
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false,
|
||||
restartOnFileChange: true
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,352 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Discussion, issues and change requests at:
|
||||
# https://github.com/nodesource/distributions
|
||||
#
|
||||
# Script to install the NodeSource Node.js 8.x LTS Carbon repo onto a
|
||||
# Debian or Ubuntu system.
|
||||
#
|
||||
# Run as root or insert `sudo -E` before `bash`:
|
||||
#
|
||||
# curl -sL https://deb.nodesource.com/setup_8.x | bash -
|
||||
# or
|
||||
# wget -qO- https://deb.nodesource.com/setup_8.x | bash -
|
||||
#
|
||||
# CONTRIBUTIONS TO THIS SCRIPT
|
||||
#
|
||||
# This script is built from a template in
|
||||
# https://github.com/nodesource/distributions/tree/master/deb/src
|
||||
# please don't submit pull requests against the built scripts.
|
||||
#
|
||||
|
||||
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
SCRSUFFIX="_8.x"
|
||||
NODENAME="Node.js 8.x LTS Carbon"
|
||||
NODEREPO="node_8.x"
|
||||
NODEPKG="nodejs"
|
||||
|
||||
print_status() {
|
||||
echo
|
||||
echo "## $1"
|
||||
echo
|
||||
}
|
||||
|
||||
if test -t 1; then # if terminal
|
||||
ncolors=$(which tput > /dev/null && tput colors) # supports color
|
||||
if test -n "$ncolors" && test $ncolors -ge 8; then
|
||||
termcols=$(tput cols)
|
||||
bold="$(tput bold)"
|
||||
underline="$(tput smul)"
|
||||
standout="$(tput smso)"
|
||||
normal="$(tput sgr0)"
|
||||
black="$(tput setaf 0)"
|
||||
red="$(tput setaf 1)"
|
||||
green="$(tput setaf 2)"
|
||||
yellow="$(tput setaf 3)"
|
||||
blue="$(tput setaf 4)"
|
||||
magenta="$(tput setaf 5)"
|
||||
cyan="$(tput setaf 6)"
|
||||
white="$(tput setaf 7)"
|
||||
fi
|
||||
fi
|
||||
|
||||
print_bold() {
|
||||
title="$1"
|
||||
text="$2"
|
||||
|
||||
echo
|
||||
echo "${red}================================================================================${normal}"
|
||||
echo "${red}================================================================================${normal}"
|
||||
echo
|
||||
echo -e " ${bold}${yellow}${title}${normal}"
|
||||
echo
|
||||
echo -en " ${text}"
|
||||
echo
|
||||
echo "${red}================================================================================${normal}"
|
||||
echo "${red}================================================================================${normal}"
|
||||
}
|
||||
|
||||
bail() {
|
||||
echo 'Error executing command, exiting'
|
||||
exit 1
|
||||
}
|
||||
|
||||
exec_cmd_nobail() {
|
||||
echo "+ $1"
|
||||
bash -c "$1"
|
||||
}
|
||||
|
||||
exec_cmd() {
|
||||
exec_cmd_nobail "$1" || bail
|
||||
}
|
||||
|
||||
node_deprecation_warning() {
|
||||
if [[ "X${NODENAME}" == "Xio.js 1.x" ||
|
||||
"X${NODENAME}" == "Xio.js 2.x" ||
|
||||
"X${NODENAME}" == "Xio.js 3.x" ||
|
||||
"X${NODENAME}" == "XNode.js 0.10" ||
|
||||
"X${NODENAME}" == "XNode.js 0.12" ||
|
||||
"X${NODENAME}" == "XNode.js 4.x LTS Argon" ||
|
||||
"X${NODENAME}" == "XNode.js 5.x" ||
|
||||
"X${NODENAME}" == "XNode.js 6.x LTS Boron" ||
|
||||
"X${NODENAME}" == "XNode.js 7.x" ||
|
||||
"X${NODENAME}" == "XNode.js 8.x LTS Carbon" ||
|
||||
"X${NODENAME}" == "XNode.js 9.x" ||
|
||||
"X${NODENAME}" == "XNode.js 10.x" ||
|
||||
"X${NODENAME}" == "XNode.js 11.x" ||
|
||||
"X${NODENAME}" == "XNode.js 13.x" ||
|
||||
"X${NODENAME}" == "XNode.js 15.x" ]]; then
|
||||
|
||||
print_bold \
|
||||
" DEPRECATION WARNING " "\
|
||||
${bold}${NODENAME} is no longer actively supported!${normal}
|
||||
|
||||
${bold}You will not receive security or critical stability updates${normal} for this version.
|
||||
|
||||
You should migrate to a supported version of Node.js as soon as possible.
|
||||
Use the installation script that corresponds to the version of Node.js you
|
||||
wish to install. e.g.
|
||||
|
||||
* ${green}https://deb.nodesource.com/setup_12.x — Node.js 12 LTS \"Erbium\"${normal}
|
||||
* ${green}https://deb.nodesource.com/setup_14.x — Node.js 14 LTS \"Fermium\"${normal} (recommended)
|
||||
* ${green}https://deb.nodesource.com/setup_16.x — Node.js 16 \"Gallium\"${normal}
|
||||
|
||||
Please see ${bold}https://github.com/nodejs/Release${normal} for details about which
|
||||
version may be appropriate for you.
|
||||
|
||||
The ${bold}NodeSource${normal} Node.js distributions repository contains
|
||||
information both about supported versions of Node.js and supported Linux
|
||||
distributions. To learn more about usage, see the repository:
|
||||
${bold}https://github.com/nodesource/distributions${normal}
|
||||
"
|
||||
echo
|
||||
echo "Continuing in 20 seconds ..."
|
||||
echo
|
||||
sleep 20
|
||||
fi
|
||||
}
|
||||
|
||||
script_deprecation_warning() {
|
||||
if [ "X${SCRSUFFIX}" == "X" ]; then
|
||||
print_bold \
|
||||
" SCRIPT DEPRECATION WARNING " "\
|
||||
This script, located at ${bold}https://deb.nodesource.com/setup${normal}, used to
|
||||
install Node.js 0.10, is deprecated and will eventually be made inactive.
|
||||
|
||||
You should use the script that corresponds to the version of Node.js you
|
||||
wish to install. e.g.
|
||||
|
||||
* ${green}https://deb.nodesource.com/setup_12.x — Node.js 12 LTS \"Erbium\"${normal}
|
||||
* ${green}https://deb.nodesource.com/setup_14.x — Node.js 14 LTS \"Fermium\"${normal} (recommended)
|
||||
* ${green}https://deb.nodesource.com/setup_16.x — Node.js 16 \"Gallium\"${normal}
|
||||
|
||||
Please see ${bold}https://github.com/nodejs/Release${normal} for details about which
|
||||
version may be appropriate for you.
|
||||
|
||||
The ${bold}NodeSource${normal} Node.js Linux distributions GitHub repository contains
|
||||
information about which versions of Node.js and which Linux distributions
|
||||
are supported and how to use the install scripts.
|
||||
${bold}https://github.com/nodesource/distributions${normal}
|
||||
"
|
||||
|
||||
echo
|
||||
echo "Continuing in 20 seconds (press Ctrl-C to abort) ..."
|
||||
echo
|
||||
sleep 20
|
||||
fi
|
||||
}
|
||||
|
||||
setup() {
|
||||
|
||||
script_deprecation_warning
|
||||
node_deprecation_warning
|
||||
|
||||
print_status "Installing the NodeSource ${NODENAME} repo..."
|
||||
|
||||
if $(uname -m | grep -Eq ^armv6); then
|
||||
print_status "You appear to be running on ARMv6 hardware. Unfortunately this is not currently supported by the NodeSource Linux distributions. Please use the 'linux-armv6l' binary tarballs available directly from nodejs.org for Node.js 4 and later."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PRE_INSTALL_PKGS=""
|
||||
|
||||
# Check that HTTPS transport is available to APT
|
||||
# (Check snaked from: https://get.docker.io/ubuntu/)
|
||||
|
||||
if [ ! -e /usr/lib/apt/methods/https ]; then
|
||||
PRE_INSTALL_PKGS="${PRE_INSTALL_PKGS} apt-transport-https"
|
||||
fi
|
||||
|
||||
if [ ! -x /usr/bin/lsb_release ]; then
|
||||
PRE_INSTALL_PKGS="${PRE_INSTALL_PKGS} lsb-release"
|
||||
fi
|
||||
|
||||
if [ ! -x /usr/bin/curl ] && [ ! -x /usr/bin/wget ]; then
|
||||
PRE_INSTALL_PKGS="${PRE_INSTALL_PKGS} curl"
|
||||
fi
|
||||
|
||||
# Used by apt-key to add new keys
|
||||
|
||||
if [ ! -x /usr/bin/gpg ]; then
|
||||
PRE_INSTALL_PKGS="${PRE_INSTALL_PKGS} gnupg"
|
||||
fi
|
||||
|
||||
# Populating Cache
|
||||
print_status "Populating apt-get cache..."
|
||||
exec_cmd 'apt-get update'
|
||||
|
||||
if [ "X${PRE_INSTALL_PKGS}" != "X" ]; then
|
||||
print_status "Installing packages required for setup:${PRE_INSTALL_PKGS}..."
|
||||
# This next command needs to be redirected to /dev/null or the script will bork
|
||||
# in some environments
|
||||
exec_cmd "apt-get install -y${PRE_INSTALL_PKGS} > /dev/null 2>&1"
|
||||
fi
|
||||
|
||||
IS_PRERELEASE=$(lsb_release -d | grep 'Ubuntu .*development' >& /dev/null; echo $?)
|
||||
if [[ $IS_PRERELEASE -eq 0 ]]; then
|
||||
print_status "Your distribution, identified as \"$(lsb_release -d -s)\", is a pre-release version of Ubuntu. NodeSource does not maintain official support for Ubuntu versions until they are formally released. You can try using the manual installation instructions available at https://github.com/nodesource/distributions and use the latest supported Ubuntu version name as the distribution identifier, although this is not guaranteed to work."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
DISTRO=$(lsb_release -c -s)
|
||||
|
||||
check_alt() {
|
||||
if [ "X${DISTRO}" == "X${2}" ]; then
|
||||
echo
|
||||
echo "## You seem to be using ${1} version ${DISTRO}."
|
||||
echo "## This maps to ${3} \"${4}\"... Adjusting for you..."
|
||||
DISTRO="${4}"
|
||||
fi
|
||||
}
|
||||
|
||||
check_alt "SolydXK" "solydxk-9" "Debian" "stretch"
|
||||
check_alt "Kali" "sana" "Debian" "jessie"
|
||||
check_alt "Kali" "kali-rolling" "Debian" "bullseye"
|
||||
check_alt "Sparky Linux" "Tyche" "Debian" "stretch"
|
||||
check_alt "Sparky Linux" "Nibiru" "Debian" "buster"
|
||||
check_alt "MX Linux 17" "Horizon" "Debian" "stretch"
|
||||
check_alt "MX Linux 18" "Continuum" "Debian" "stretch"
|
||||
check_alt "MX Linux 19" "patito feo" "Debian" "buster"
|
||||
check_alt "Linux Mint" "maya" "Ubuntu" "precise"
|
||||
check_alt "Linux Mint" "qiana" "Ubuntu" "trusty"
|
||||
check_alt "Linux Mint" "rafaela" "Ubuntu" "trusty"
|
||||
check_alt "Linux Mint" "rebecca" "Ubuntu" "trusty"
|
||||
check_alt "Linux Mint" "rosa" "Ubuntu" "trusty"
|
||||
check_alt "Linux Mint" "sarah" "Ubuntu" "xenial"
|
||||
check_alt "Linux Mint" "serena" "Ubuntu" "xenial"
|
||||
check_alt "Linux Mint" "sonya" "Ubuntu" "xenial"
|
||||
check_alt "Linux Mint" "sylvia" "Ubuntu" "xenial"
|
||||
check_alt "Linux Mint" "tara" "Ubuntu" "bionic"
|
||||
check_alt "Linux Mint" "tessa" "Ubuntu" "bionic"
|
||||
check_alt "Linux Mint" "tina" "Ubuntu" "bionic"
|
||||
check_alt "Linux Mint" "tricia" "Ubuntu" "bionic"
|
||||
check_alt "Linux Mint" "ulyana" "Ubuntu" "focal"
|
||||
check_alt "Linux Mint" "ulyssa" "Ubuntu" "focal"
|
||||
check_alt "Linux Mint" "uma" "Ubuntu" "focal"
|
||||
check_alt "LMDE" "betsy" "Debian" "jessie"
|
||||
check_alt "LMDE" "cindy" "Debian" "stretch"
|
||||
check_alt "LMDE" "debbie" "Debian" "buster"
|
||||
check_alt "elementaryOS" "luna" "Ubuntu" "precise"
|
||||
check_alt "elementaryOS" "freya" "Ubuntu" "trusty"
|
||||
check_alt "elementaryOS" "loki" "Ubuntu" "xenial"
|
||||
check_alt "elementaryOS" "juno" "Ubuntu" "bionic"
|
||||
check_alt "elementaryOS" "hera" "Ubuntu" "bionic"
|
||||
check_alt "elementaryOS" "odin" "Ubuntu" "focal"
|
||||
check_alt "Trisquel" "toutatis" "Ubuntu" "precise"
|
||||
check_alt "Trisquel" "belenos" "Ubuntu" "trusty"
|
||||
check_alt "Trisquel" "flidas" "Ubuntu" "xenial"
|
||||
check_alt "Trisquel" "etiona" "Ubuntu" "bionic"
|
||||
check_alt "Uruk GNU/Linux" "lugalbanda" "Ubuntu" "xenial"
|
||||
check_alt "BOSS" "anokha" "Debian" "wheezy"
|
||||
check_alt "BOSS" "anoop" "Debian" "jessie"
|
||||
check_alt "BOSS" "drishti" "Debian" "stretch"
|
||||
check_alt "BOSS" "unnati" "Debian" "buster"
|
||||
check_alt "bunsenlabs" "bunsen-hydrogen" "Debian" "jessie"
|
||||
check_alt "bunsenlabs" "helium" "Debian" "stretch"
|
||||
check_alt "bunsenlabs" "lithium" "Debian" "buster"
|
||||
check_alt "Tanglu" "chromodoris" "Debian" "jessie"
|
||||
check_alt "PureOS" "green" "Debian" "sid"
|
||||
check_alt "PureOS" "amber" "Debian" "buster"
|
||||
check_alt "Devuan" "jessie" "Debian" "jessie"
|
||||
check_alt "Devuan" "ascii" "Debian" "stretch"
|
||||
check_alt "Devuan" "beowulf" "Debian" "buster"
|
||||
check_alt "Devuan" "ceres" "Debian" "sid"
|
||||
check_alt "Deepin" "panda" "Debian" "sid"
|
||||
check_alt "Deepin" "unstable" "Debian" "sid"
|
||||
check_alt "Deepin" "stable" "Debian" "buster"
|
||||
check_alt "Pardus" "onyedi" "Debian" "stretch"
|
||||
check_alt "Liquid Lemur" "lemur-3" "Debian" "stretch"
|
||||
check_alt "Astra Linux" "orel" "Debian" "stretch"
|
||||
check_alt "Ubilinux" "dolcetto" "Debian" "stretch"
|
||||
|
||||
if [ "X${DISTRO}" == "Xdebian" ]; then
|
||||
print_status "Unknown Debian-based distribution, checking /etc/debian_version..."
|
||||
NEWDISTRO=$([ -e /etc/debian_version ] && cut -d/ -f1 < /etc/debian_version)
|
||||
if [ "X${NEWDISTRO}" == "X" ]; then
|
||||
print_status "Could not determine distribution from /etc/debian_version..."
|
||||
else
|
||||
DISTRO=$NEWDISTRO
|
||||
print_status "Found \"${DISTRO}\" in /etc/debian_version..."
|
||||
fi
|
||||
fi
|
||||
|
||||
print_status "Confirming \"${DISTRO}\" is supported..."
|
||||
|
||||
if [ -x /usr/bin/curl ]; then
|
||||
exec_cmd_nobail "curl -sLf -o /dev/null 'https://deb.nodesource.com/${NODEREPO}/dists/${DISTRO}/Release'"
|
||||
RC=$?
|
||||
else
|
||||
exec_cmd_nobail "wget -qO /dev/null -o /dev/null 'https://deb.nodesource.com/${NODEREPO}/dists/${DISTRO}/Release'"
|
||||
RC=$?
|
||||
fi
|
||||
|
||||
if [[ $RC != 0 ]]; then
|
||||
print_status "Your distribution, identified as \"${DISTRO}\", is not currently supported, please contact NodeSource at https://github.com/nodesource/distributions/issues if you think this is incorrect or would like your distribution to be considered for support"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -f "/etc/apt/sources.list.d/chris-lea-node_js-$DISTRO.list" ]; then
|
||||
print_status 'Removing Launchpad PPA Repository for NodeJS...'
|
||||
|
||||
exec_cmd_nobail 'add-apt-repository -y -r ppa:chris-lea/node.js'
|
||||
exec_cmd "rm -f /etc/apt/sources.list.d/chris-lea-node_js-${DISTRO}.list"
|
||||
fi
|
||||
|
||||
print_status 'Adding the NodeSource signing key to your keyring...'
|
||||
keyring='/usr/share/keyrings'
|
||||
node_key_url="https://deb.nodesource.com/gpgkey/nodesource.gpg.key"
|
||||
local_node_key="$keyring/nodesource.gpg"
|
||||
|
||||
if [ -x /usr/bin/curl ]; then
|
||||
exec_cmd "curl -s $node_key_url | gpg --dearmor | tee $local_node_key >/dev/null"
|
||||
else
|
||||
exec_cmd "wget -q -O - $node_key_url | gpg --dearmor | tee $local_node_key >/dev/null"
|
||||
fi
|
||||
|
||||
print_status "Creating apt sources list file for the NodeSource ${NODENAME} repo..."
|
||||
|
||||
exec_cmd "echo 'deb [signed-by=$local_node_key] https://deb.nodesource.com/${NODEREPO} ${DISTRO} main' > /etc/apt/sources.list.d/nodesource.list"
|
||||
exec_cmd "echo 'deb-src [signed-by=$local_node_key] https://deb.nodesource.com/${NODEREPO} ${DISTRO} main' >> /etc/apt/sources.list.d/nodesource.list"
|
||||
|
||||
print_status 'Running `apt-get update` for you...'
|
||||
|
||||
exec_cmd 'apt-get update'
|
||||
|
||||
yarn_site='https://dl.yarnpkg.com/debian'
|
||||
yarn_key_url="$yarn_site/pubkey.gpg"
|
||||
local_yarn_key="$keyring/yarnkey.gpg"
|
||||
|
||||
print_status """Run \`${bold}sudo apt-get install -y ${NODEPKG}${normal}\` to install ${NODENAME} and npm
|
||||
## You may also need development tools to build native addons:
|
||||
sudo apt-get install gcc g++ make
|
||||
## To install the Yarn package manager, run:
|
||||
curl -sL $yarn_key_url | gpg --dearmor | sudo tee $local_yarn_key >/dev/null
|
||||
echo \"deb [signed-by=$local_yarn_key] $yarn_site stable main\" | sudo tee /etc/apt/sources.list.d/yarn.list
|
||||
sudo apt-get update && sudo apt-get install yarn
|
||||
"""
|
||||
|
||||
}
|
||||
|
||||
## Defer setup until we have the complete script
|
||||
setup
|
||||
Generated
+26856
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,91 @@
|
||||
{
|
||||
"name": "multikart-backend",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"build": "ng build",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@ag-grid-community/angular": "^27.3.0",
|
||||
"@ag-grid-community/client-side-row-model": "^27.3.0",
|
||||
"@ag-grid-community/core": "^27.3.0",
|
||||
"@akveo/ng2-completer": "^9.0.1",
|
||||
"@angular/animations": "^15.0.2",
|
||||
"@angular/cdk": "^13.3.7",
|
||||
"@angular/common": "^15.0.2",
|
||||
"@angular/compiler": "^15.0.2",
|
||||
"@angular/core": "^15.0.2",
|
||||
"@angular/fire": "^7.5.0",
|
||||
"@angular/forms": "^15.0.2",
|
||||
"@angular/localize": "^15.0.2",
|
||||
"@angular/platform-browser": "^15.0.2",
|
||||
"@angular/platform-browser-dynamic": "^15.0.2",
|
||||
"@angular/router": "^15.0.2",
|
||||
"@ckeditor/ckeditor5-angular": "^4.0.0",
|
||||
"@ckeditor/ckeditor5-build-classic": "^34.0.0",
|
||||
"@ks89/angular-modal-gallery": "^9.1.0",
|
||||
"@ng-bootstrap/ng-bootstrap": "^13.1.1",
|
||||
"@popperjs/core": "^2.11.6",
|
||||
"@swimlane/ngx-charts": "^20.1.0",
|
||||
"ag-grid-angular": "^27.3.0",
|
||||
"ag-grid-community": "^27.3.0",
|
||||
"angular-count-to": "0.0.3",
|
||||
"bootstrap": "^4.1.3",
|
||||
"chart.js": "^3.7.1",
|
||||
"chartist": "^0.11.4",
|
||||
"express": "^4.18.1",
|
||||
"feather-icons": "^4.29.0",
|
||||
"firebase": "^9.17.1",
|
||||
"flag-icons": "^6.3.0",
|
||||
"font-awesome": "^4.7.0",
|
||||
"hammerjs": "^2.0.8",
|
||||
"mousetrap": "^1.6.5",
|
||||
"ng-animate": "^1.0.0",
|
||||
"ng-chartist": "^6.7.0",
|
||||
"ng-image-slider": "^7.0.0",
|
||||
"ng2-charts": "^3.0.11",
|
||||
"ng2-completer": "^9.0.1",
|
||||
"ng2-google-charts": "^7.0.0",
|
||||
"ng2-search-filter": "^0.5.1",
|
||||
"ngx-bootstrap": "^10.2.0",
|
||||
"ngx-dropzone": "^3.1.0",
|
||||
"ngx-dropzone-wrapper": "^11.0.0",
|
||||
"ngx-owl-carousel-o": "^14.0.0",
|
||||
"ngx-slimscroll": "^12.2.0",
|
||||
"ngx-toastr": "^16.1.0",
|
||||
"rxjs": "~7.5.5",
|
||||
"rxjs-compat": "^6.6.7",
|
||||
"sass": "~1.51.0",
|
||||
"screenfull": "^6.0.1",
|
||||
"socket.io-client": "^4.6.1",
|
||||
"tslib": "^2.4.0",
|
||||
"zone.js": "~0.11.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "^15.0.2",
|
||||
"@angular/cli": "^15.0.2",
|
||||
"@angular/compiler-cli": "^15.0.2",
|
||||
"@angular/language-service": "^15.0.2",
|
||||
"@types/chart.js": "^2.9.37",
|
||||
"@types/jasmine": "~4.0.3",
|
||||
"@types/jasminewd2": "~2.0.10",
|
||||
"@types/node": "^17.0.33",
|
||||
"codelyzer": "^6.0.2",
|
||||
"jasmine-core": "~4.1.1",
|
||||
"jasmine-spec-reporter": "~7.0.0",
|
||||
"karma": "~6.3.20",
|
||||
"karma-chrome-launcher": "~3.1.1",
|
||||
"karma-coverage-istanbul-reporter": "~3.0.3",
|
||||
"karma-jasmine": "~5.0.1",
|
||||
"karma-jasmine-html-reporter": "^1.7.0",
|
||||
"protractor": "~7.0.0",
|
||||
"ts-node": "~10.7.0",
|
||||
"tslint": "~6.1.0",
|
||||
"typescript": "~4.8.4"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
import { content } from './shared/routes/content-routes';
|
||||
import { ContentLayoutComponent } from './shared/layout/content-layout/content-layout.component';
|
||||
import { LoginComponent } from './components/auth/login/login.component';
|
||||
import { SignupComponent } from './components/auth/signup/signup.component';
|
||||
import { ForbiddenComponent } from './components/auth/forbidden/forbidden.component';
|
||||
import { ResetPasswordComponent } from './components/auth/reset-password/reset-password.component';
|
||||
import { NotLogged } from './shared/guard/not-logged.service';
|
||||
import { EmailVerifiedComponent } from './components/auth/email-verified/email-verified.component';
|
||||
import { EmailNotVerifiedComponent } from './components/auth/email-not-verified/email-not-verified.component';
|
||||
import { SendEmailComponent } from './components/auth/send-email/send-email.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
redirectTo: '/dashboard/default',
|
||||
pathMatch: 'full'
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
component: ContentLayoutComponent,
|
||||
children: content
|
||||
},
|
||||
{
|
||||
path: 'auth/login',
|
||||
canActivate: [NotLogged],
|
||||
component: LoginComponent,
|
||||
},
|
||||
{
|
||||
path: 'auth/signup',
|
||||
canActivate: [NotLogged],
|
||||
component: SignupComponent
|
||||
},
|
||||
{
|
||||
path: 'auth/send-email',
|
||||
canActivate: [NotLogged],
|
||||
component: SendEmailComponent
|
||||
},
|
||||
{
|
||||
path: 'auth/forbidden',
|
||||
canActivate: [NotLogged],
|
||||
component: ForbiddenComponent
|
||||
},
|
||||
{
|
||||
path: 'auth/reset-password',
|
||||
canActivate: [NotLogged],
|
||||
component: ResetPasswordComponent
|
||||
},
|
||||
{
|
||||
path: 'auth/email-verified',
|
||||
canActivate: [NotLogged],
|
||||
component: EmailVerifiedComponent
|
||||
},
|
||||
{
|
||||
path: 'auth/email-not-verified',
|
||||
canActivate: [NotLogged],
|
||||
component: EmailNotVerifiedComponent
|
||||
},
|
||||
{
|
||||
path: '**', // Navigate to Home Page if not found any page
|
||||
redirectTo: '/dashboard/default',
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forRoot(routes, {
|
||||
scrollPositionRestoration: 'enabled'
|
||||
})],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class AppRoutingModule { }
|
||||
@@ -0,0 +1 @@
|
||||
<router-outlet></router-outlet>
|
||||
@@ -0,0 +1,10 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.scss']
|
||||
})
|
||||
export class AppComponent {
|
||||
title = 'foodify-backend';
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { AgGridModule } from '@ag-grid-community/angular';
|
||||
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { AppComponent } from './app.component';
|
||||
|
||||
import { DashboardModule } from './components/dashboard/dashboard.module';
|
||||
import { SharedModule } from './shared/shared.module';
|
||||
import { ProductsModule } from './components/products/products.module';
|
||||
import { SalesModule } from './components/sales/sales.module';
|
||||
import { CouponsModule } from './components/coupons/coupons.module';
|
||||
import { PagesModule } from './components/pages/pages.module';
|
||||
import { MediaModule } from './components/media/media.module';
|
||||
import { MenusModule } from './components/menus/menus.module';
|
||||
import { VendorsModule } from './components/vendors/vendors.module';
|
||||
import { UsersModule } from './components/users/users.module';
|
||||
import { LocalizationModule } from './components/localization/localization.module';
|
||||
import { InvoiceModule } from './components/invoice/invoice.module';
|
||||
import { SettingModule } from './components/setting/setting.module';
|
||||
import { ReportsModule } from './components/reports/reports.module';
|
||||
import { AuthModule } from './components/auth/auth.module';
|
||||
import { HTTP_INTERCEPTORS, HttpClientModule } from "@angular/common/http";
|
||||
import { ModalModule } from "ngx-bootstrap/modal";
|
||||
import { AngularFireStorageModule } from "@angular/fire/compat/storage";
|
||||
import { AngularFireModule } from "@angular/fire/compat";
|
||||
import { environment } from "../environments/environment";
|
||||
import { FirebaseService } from "./shared/service/firebase.service";
|
||||
import { AuthInterceptor } from "./shared/inceptor/auth-interceptor";
|
||||
import { NgImageSliderModule } from 'ng-image-slider'
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent,
|
||||
],
|
||||
imports: [
|
||||
BrowserAnimationsModule,
|
||||
BrowserModule.withServerTransition({ appId: 'serverApp' }),
|
||||
AppRoutingModule,
|
||||
DashboardModule,
|
||||
InvoiceModule,
|
||||
SettingModule,
|
||||
ReportsModule,
|
||||
AuthModule,
|
||||
SharedModule,
|
||||
LocalizationModule,
|
||||
ProductsModule,
|
||||
SalesModule,
|
||||
// NgImageSliderModule,
|
||||
VendorsModule,
|
||||
CouponsModule,
|
||||
PagesModule,
|
||||
MediaModule,
|
||||
MenusModule,
|
||||
UsersModule,
|
||||
AgGridModule,
|
||||
HttpClientModule,
|
||||
AngularFireStorageModule,
|
||||
AngularFireModule.initializeApp(environment.firebaseConfig, 'cloud'),
|
||||
ModalModule.forRoot()
|
||||
|
||||
],
|
||||
providers: [
|
||||
FirebaseService,
|
||||
{
|
||||
provide: HTTP_INTERCEPTORS,
|
||||
useClass: AuthInterceptor,
|
||||
multi: true
|
||||
}
|
||||
],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule {
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import { NgModule } from "@angular/core";
|
||||
import { Routes, RouterModule } from "@angular/router";
|
||||
import { LoginComponent } from "./login/login.component";
|
||||
import { ForbiddenComponent } from "./forbidden/forbidden.component";
|
||||
import { SignupComponent } from "./signup/signup.component";
|
||||
import { ResetPasswordComponent } from "./reset-password/reset-password.component";
|
||||
import { SendEmailComponent } from "./send-email/send-email.component";
|
||||
import { EmailVerifiedComponent } from "./email-verified/email-verified.component";
|
||||
|
||||
const routes: Routes = [
|
||||
// {
|
||||
// path: "login",
|
||||
// component: LoginComponent,
|
||||
// },
|
||||
// {
|
||||
// path: "forbidden",
|
||||
// component: ForbiddenComponent,
|
||||
// },
|
||||
// {
|
||||
// path: "signup",
|
||||
// component: SignupComponent,
|
||||
// },
|
||||
// {
|
||||
// path: "send-email",
|
||||
// component: SendEmailComponent,
|
||||
// },
|
||||
// {
|
||||
// path: "reset-password",
|
||||
// component: ResetPasswordComponent,
|
||||
// },
|
||||
// {
|
||||
// path: "email-verified",
|
||||
// component: EmailVerifiedComponent,
|
||||
// },
|
||||
// {
|
||||
// path: "email-not-verified",
|
||||
// component: EmailVerifiedComponent,
|
||||
// }
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class AuthRoutingModule { }
|
||||
@@ -0,0 +1,29 @@
|
||||
import { NgModule } from "@angular/core";
|
||||
import { CommonModule } from "@angular/common";
|
||||
|
||||
import { AuthRoutingModule } from "./auth-routing.module";
|
||||
import { LoginComponent } from "./login/login.component";
|
||||
|
||||
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
|
||||
import { NgbModule } from "@ng-bootstrap/ng-bootstrap";
|
||||
import { CarouselModule } from "ngx-owl-carousel-o";
|
||||
import { SharedModule } from "../../shared/shared.module";
|
||||
import { ForbiddenComponent } from "./forbidden/forbidden.component";
|
||||
import { SignupComponent } from "./signup/signup.component";
|
||||
import { ResetPasswordComponent } from './reset-password/reset-password.component';
|
||||
import { SendEmailComponent } from './send-email/send-email.component';
|
||||
import { EmailVerifiedComponent } from './email-verified/email-verified.component';
|
||||
import { EmailNotVerifiedComponent } from './email-not-verified/email-not-verified.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [LoginComponent, SignupComponent, ForbiddenComponent, ResetPasswordComponent, SendEmailComponent, EmailVerifiedComponent, EmailNotVerifiedComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
AuthRoutingModule,
|
||||
ReactiveFormsModule,
|
||||
CarouselModule,
|
||||
SharedModule,
|
||||
NgbModule,
|
||||
FormsModule],
|
||||
})
|
||||
export class AuthModule { }
|
||||
@@ -0,0 +1,15 @@
|
||||
<!-- Container-fluid starts-->
|
||||
<div class="backgound-food d-flex justify-content-center align-items-center">
|
||||
<div class="forbidden-box d-flex flex-column justify-content-center align-items-center responsive-box">
|
||||
<img class="forbidden-img" src="../../../../assets/images/dashboard/403-forbidden.png">
|
||||
<div class="forbidden-text"><span>Email</span> Not Verified</div>
|
||||
<div class="forbidden-desc mt-1 mb-4">
|
||||
<div>Tài khoản của bạn chưa được xác minh.</div>
|
||||
<div>Vui lòng kiểm tra email để kích hoạt tài khoản.</div>
|
||||
</div>
|
||||
<div class="forbidden-btn">
|
||||
<button class="btn btn-primary return-btn" (click)="goToGmail()">Đi tới mail</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Container-fluid Ends-->
|
||||
@@ -0,0 +1,60 @@
|
||||
.backgound-food {
|
||||
background-image: url("../../../../assets/images/background-login.jpg");
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
z-index: -99;
|
||||
|
||||
.forbidden-box {
|
||||
width: 822px;
|
||||
// height: 536px;
|
||||
background-color: #fff;
|
||||
padding: 16px 110px 40px;
|
||||
border-radius: 10px;
|
||||
box-shadow: rgb(38, 57, 77) 0px 20px 30px -10px;
|
||||
|
||||
.forbidden-img {
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
.forbidden-text {
|
||||
font-family: 'Sedgwick Ave Display', cursive;
|
||||
text-transform: uppercase;
|
||||
font-size: 50px;
|
||||
|
||||
span {
|
||||
color: lightcoral;
|
||||
font-size: 60px;
|
||||
}
|
||||
}
|
||||
|
||||
.forbidden-desc {
|
||||
font-size: 20px;
|
||||
text-align: center;
|
||||
font-family: 'Nunito', sans-serif;
|
||||
}
|
||||
|
||||
.forbidden-btn {}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width:768px) {
|
||||
.backgound-food {
|
||||
background-image: none;
|
||||
|
||||
.responsive-box {
|
||||
width: 86%;
|
||||
padding: 16px 20px 40px;
|
||||
|
||||
.forbidden-img {
|
||||
max-width: 248px;
|
||||
}
|
||||
|
||||
.forbidden-text {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { EmailNotVerifiedComponent } from './email-not-verified.component';
|
||||
|
||||
describe('EmailNotVerifiedComponent', () => {
|
||||
let component: EmailNotVerifiedComponent;
|
||||
let fixture: ComponentFixture<EmailNotVerifiedComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ EmailNotVerifiedComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(EmailNotVerifiedComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,12 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-email-not-verified',
|
||||
templateUrl: './email-not-verified.component.html',
|
||||
styleUrls: ['./email-not-verified.component.scss']
|
||||
})
|
||||
export class EmailNotVerifiedComponent {
|
||||
goToGmail() {
|
||||
window.location.assign("https://mail.google.com/");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<!-- Container-fluid starts-->
|
||||
<div class="backgound-food d-flex justify-content-center align-items-center">
|
||||
<div class="forbidden-box d-flex flex-column justify-content-center align-items-center responsive-box">
|
||||
<img class="forbidden-img" src="../../../../assets/images/dashboard/verified-vuong.png">
|
||||
<div class="forbidden-text"><span>Email</span> Verified</div>
|
||||
<div class="forbidden-desc mt-1 mb-4">
|
||||
<div>Tài khoản của bạn đã được xác minh</div>
|
||||
</div>
|
||||
<div class="forbidden-btn w-100 d-flex justify-content-around align-items-center ">
|
||||
<button class="btn btn-primary return-btn" [routerLink]="['/auth', 'login']">Đăng nhập cửa hàng</button>
|
||||
<a href="https://foodify-fpt.vercel.app/home/login"><button class="btn btn-info return-btn">Đăng nhập
|
||||
người dùng</button></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Container-fluid Ends-->
|
||||
@@ -0,0 +1,60 @@
|
||||
.backgound-food {
|
||||
background-image: url("../../../../assets/images/background-login.jpg");
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
z-index: -99;
|
||||
|
||||
.forbidden-box {
|
||||
width: 822px;
|
||||
// height: 536px;
|
||||
background-color: #fff;
|
||||
padding: 16px 110px 40px;
|
||||
border-radius: 10px;
|
||||
box-shadow: rgb(38, 57, 77) 0px 20px 30px -10px;
|
||||
|
||||
.forbidden-img {
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
.forbidden-text {
|
||||
font-family: 'Sedgwick Ave Display', cursive;
|
||||
text-transform: uppercase;
|
||||
font-size: 50px;
|
||||
|
||||
span {
|
||||
color: rgb(128, 240, 186);
|
||||
font-size: 60px;
|
||||
}
|
||||
}
|
||||
|
||||
.forbidden-desc {
|
||||
font-size: 20px;
|
||||
text-align: center;
|
||||
font-family: 'Nunito', sans-serif;
|
||||
}
|
||||
|
||||
.forbidden-btn {}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width:768px) {
|
||||
.backgound-food {
|
||||
background-image: none;
|
||||
|
||||
.responsive-box {
|
||||
width: 86%;
|
||||
padding: 16px 20px 40px;
|
||||
|
||||
.forbidden-img {
|
||||
max-width: 248px;
|
||||
}
|
||||
|
||||
.forbidden-text {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { EmailVerifiedComponent } from './email-verified.component';
|
||||
|
||||
describe('EmailVerifiedComponent', () => {
|
||||
let component: EmailVerifiedComponent;
|
||||
let fixture: ComponentFixture<EmailVerifiedComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ EmailVerifiedComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(EmailVerifiedComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-email-verified',
|
||||
templateUrl: './email-verified.component.html',
|
||||
styleUrls: ['./email-verified.component.scss']
|
||||
})
|
||||
export class EmailVerifiedComponent {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<!-- Container-fluid starts-->
|
||||
<div class="backgound-food d-flex justify-content-center align-items-center">
|
||||
<div class="forbidden-box d-flex flex-column justify-content-center align-items-center responsive-box">
|
||||
<img class="forbidden-img" src="../../../../assets/images/dashboard/403-forbidden.png">
|
||||
<div class="forbidden-text"><span>403</span> Forbidden</div>
|
||||
<div class="forbidden-desc mt-1 mb-4">
|
||||
<div>Bạn không có quyền truy cập vào trang web này</div>
|
||||
<div>hoặc tài khoản của bạn đã bị khoá.</div>
|
||||
</div>
|
||||
<div class="forbidden-btn">
|
||||
<button class="btn btn-primary return-btn" [routerLink]="['/auth', 'login']">Quay về</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Container-fluid Ends-->
|
||||
@@ -0,0 +1,66 @@
|
||||
|
||||
|
||||
.backgound-food {
|
||||
background-image: url("../../../../assets/images/background-login.jpg");
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
z-index: -99;
|
||||
|
||||
.forbidden-box {
|
||||
width: 822px;
|
||||
// height: 536px;
|
||||
background-color: #fff;
|
||||
padding: 16px 110px 40px;
|
||||
border-radius: 10px;
|
||||
box-shadow: rgb(38, 57, 77) 0px 20px 30px -10px;
|
||||
|
||||
.forbidden-img {
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
.forbidden-text {
|
||||
font-family: 'Sedgwick Ave Display', cursive;
|
||||
text-transform: uppercase;
|
||||
font-size: 50px;
|
||||
|
||||
span {
|
||||
color: lightcoral;
|
||||
font-size: 60px;
|
||||
}
|
||||
}
|
||||
|
||||
.forbidden-desc {
|
||||
font-size: 20px;
|
||||
text-align: center;
|
||||
font-family: 'Nunito', sans-serif;
|
||||
}
|
||||
|
||||
.forbidden-btn {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width:768px) {
|
||||
.backgound-food {
|
||||
background-image: none;
|
||||
|
||||
.responsive-box {
|
||||
width: 86%;
|
||||
padding: 16px 20px 40px;
|
||||
|
||||
.forbidden-img {
|
||||
max-width: 248px;
|
||||
}
|
||||
|
||||
.forbidden-text {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-forbidden',
|
||||
templateUrl: './forbidden.component.html',
|
||||
styleUrls: ['./forbidden.component.scss']
|
||||
})
|
||||
export class ForbiddenComponent {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
<div class="page-wrapper">
|
||||
<div class="authentication-box backgound-food">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-5 p-0 card-left disable-pink">
|
||||
<div class="card bg-primary">
|
||||
<div class="svg-icon">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 468.52 468.52"
|
||||
style="enable-background:new 0 0 468.52 468.52;" xml:space="preserve">
|
||||
<g>
|
||||
<path style="fill:#E6E6E6;" d="M468.52,102.595v251.88c0,11.14-7.571,20.52-17.86,23.25c-1.98,0.531-4.06,0.81-6.2,0.81H38.58
|
||||
c-13.29,0-24.061-10.77-24.061-24.06v-251.88c0-13.29,10.771-24.06,24.061-24.06h405.88c2.14,0,4.22,0.28,6.2,0.81
|
||||
C460.949,82.075,468.52,91.455,468.52,102.595" />
|
||||
<path style="fill:#B3B3B3;" d="M468.518,102.591v23.94h-454v-23.94c0-13.29,10.771-24.06,24.06-24.06h405.88
|
||||
C457.747,78.532,468.518,89.302,468.518,102.591" />
|
||||
<rect x="42.099" y="141.002" style="fill:#999999;" width="118.901"
|
||||
height="16.532" />
|
||||
<polyline style="fill:#FFFFFF;"
|
||||
points="442.383,222.765 256.652,222.765 256.652,354.496 442.383,354.496 442.383,222.765 " />
|
||||
<polyline style="fill:#13c9ca;"
|
||||
points="434.552,329.733 265.552,329.733 265.552,346.265 434.552,346.265 434.552,329.733 " />
|
||||
<polyline style="fill:#a5a5a5;"
|
||||
points="286.552,297.744 265.552,297.744 265.552,314.276 286.552,314.276 286.552,297.744 " />
|
||||
<polyline style="fill:#ffbc58;"
|
||||
points="350.552,265.754 265.552,265.754 265.552,282.286 350.552,282.286 350.552,265.754 " />
|
||||
<polyline style="fill:#999999;"
|
||||
points="411.552,233.765 265.552,233.765 265.552,250.297 411.552,250.297 411.552,233.765 " />
|
||||
<circle style="fill:#a5a5a5;" cx="47.517" cy="102.532" r="15" />
|
||||
<circle style="fill:#ffbc58;" cx="87.517" cy="102.532" r="15" />
|
||||
<path style="fill:#EEEEEE;" d="M463.696,88.139c3.027,4.024,4.822,9.029,4.822,14.453v23.94h-23.321
|
||||
c0.04,35.899-19.42,70.584-53.444,88.347c-2.102,0.921-4.223,1.779-6.365,2.574l2.774,5.313h54.222v131.731H298.563l7.326,24.038
|
||||
h138.57c2.14,0,4.22-0.28,6.2-0.81c10.29-2.73,17.86-12.11,17.86-23.25v-251.88C468.52,97.17,466.725,92.164,463.696,88.139
|
||||
M463.657,88.088c0.012,0.016,0.023,0.031,0.036,0.047C463.681,88.12,463.669,88.103,463.657,88.088 M463.621,88.04
|
||||
c0.008,0.01,0.015,0.02,0.023,0.03C463.636,88.06,463.629,88.05,463.621,88.04 M463.59,87.999c0.003,0.004,0.006,0.008,0.009,0.012
|
||||
C463.596,88.007,463.593,88.003,463.59,87.999" />
|
||||
<path style="fill:#CBCBCB;" d="M444.46,78.535h-11.739c0.396,0.716,0.784,1.437,1.165,2.167c7.655,14.662,11.293,30.36,11.31,45.83
|
||||
h23.321v-23.94c0-5.424-1.795-10.429-4.822-14.453l0,0c-0.001-0.001-0.002-0.002-0.003-0.003l0,0
|
||||
c-0.012-0.016-0.023-0.031-0.036-0.047l0,0c-0.005-0.006-0.009-0.012-0.014-0.018l0,0c-0.008-0.01-0.015-0.02-0.023-0.03l0,0
|
||||
c-0.007-0.01-0.014-0.019-0.022-0.029l0,0c-0.003-0.004-0.006-0.008-0.009-0.012l0,0c-3.187-4.171-7.708-7.269-12.93-8.654
|
||||
C448.68,78.815,446.6,78.535,444.46,78.535" />
|
||||
<path style="fill:#FFFFFF;" d="M442.383,222.765h-54.222l5.326,10.202c-0.519,0.271-1.04,0.537-1.561,0.798h19.626v16.532H266.807
|
||||
l4.711,15.457h79.034v16.532h-73.996l4.711,15.458h5.285v16.532h-0.246l4.711,15.457h143.536v16.532H296.055l2.509,8.231h143.819
|
||||
V222.765" />
|
||||
<polyline style="fill:#6EC6EB;"
|
||||
points="434.552,329.733 291.016,329.733 296.055,346.265 434.552,346.265 434.552,329.733 " />
|
||||
<polyline style="fill:#FDA589;"
|
||||
points="286.552,297.744 281.267,297.744 286.306,314.276 286.552,314.276 286.552,297.744 " />
|
||||
<polyline style="fill:#FBE98E;"
|
||||
points="350.552,265.754 271.518,265.754 276.556,282.286 350.552,282.286 350.552,265.754 " />
|
||||
<path style="fill:#EEEEEE;" d="M246.265,126.531h-17.178l29.329,96.234h62.908c-1.465-0.282-2.926-0.591-4.384-0.929l-1.001-0.232
|
||||
c-24.282-7.625-45.651-24.51-58.362-48.855C249.857,157.962,246.221,142.128,246.265,126.531" />
|
||||
<path style="fill:#CBCBCB;" d="M258.73,78.535h-44.27l14.628,47.996h17.178c0.028-10.08,1.594-20.062,4.587-29.594
|
||||
C252.852,90.569,255.489,84.4,258.73,78.535" />
|
||||
<path style="fill:#FFFFFF;" d="M321.324,222.765h-62.908l7.136,23.415v-12.415h53.983l3.362-10.708
|
||||
C322.373,222.963,321.848,222.866,321.324,222.765" />
|
||||
<path style="fill:#BABABA;" d="M411.552,233.765h-19.626c-14.25,7.129-29.421,10.514-44.383,10.514
|
||||
c-10.173,0-20.251-1.566-29.869-4.586l1.861-5.928h-53.983v12.415l1.255,4.117h144.745V233.765" />
|
||||
<path style="fill:#CECECE;"
|
||||
d="M385.387,217.453c-6.196,2.3-12.551,4.073-18.994,5.313h21.767L385.387,217.453" />
|
||||
<path style="fill:#DBDBDB;"
|
||||
d="M388.161,222.765h-21.767c-7.428,1.428-14.973,2.147-22.536,2.147
|
||||
c-6.999,0-14.015-0.616-20.959-1.855l-3.362,10.708h72.391c0.521-0.261,1.042-0.527,1.561-0.798L388.161,222.765" />
|
||||
<path style="fill:#A4A4A4;" d="M391.926,233.765h-72.391l-1.861,5.928c9.618,3.02,19.696,4.586,29.869,4.586
|
||||
C362.505,244.279,377.677,240.894,391.926,233.765" />
|
||||
<path style="fill:#DBDBDB;" d="M345.64,27.261c-15.507,0-31.24,3.637-45.936,11.309c-17.955,9.374-31.855,23.466-40.973,39.961
|
||||
h173.987c-12.828-23.18-33.641-39.288-57.199-46.682C365.898,28.829,355.817,27.261,345.64,27.261" />
|
||||
<polyline style="fill:#9F9F9F;"
|
||||
points="432.719,78.532 258.732,78.532 258.73,78.535 432.721,78.535 432.719,78.532 " />
|
||||
<path style="fill:#CECECE;"
|
||||
d="M445.196,126.531H246.265c-0.044,15.597,3.592,31.43,11.312,46.218
|
||||
c12.711,24.345,34.08,41.23,58.362,48.855l1.001,0.232c1.458,0.338,2.919,0.647,4.384,0.929h45.069
|
||||
c6.443-1.239,12.797-3.012,18.994-5.313c2.142-0.795,4.263-1.653,6.365-2.574C425.776,197.115,445.237,162.431,445.196,126.531" />
|
||||
<path style="fill:#B2B2B2;" d="M432.721,78.535H258.73c-3.241,5.865-5.878,12.033-7.878,18.402
|
||||
c-2.993,9.532-4.559,19.515-4.587,29.594h198.931c-0.017-15.469-3.656-31.168-11.31-45.83
|
||||
C433.505,79.972,433.117,79.251,432.721,78.535" />
|
||||
<path style="fill:#DBDBDB;" d="M366.393,222.765h-45.069c0.524,0.101,1.049,0.198,1.574,0.292
|
||||
c6.945,1.239,13.96,1.855,20.959,1.855C351.42,224.912,358.965,224.193,366.393,222.765" />
|
||||
<path style="fill:#ffbc58;" d="M345.73,113.225l-5.24,16.69l-24.55,78.18c-24.28-7.62-45.65-24.51-58.36-48.85
|
||||
c-12.71-24.35-14.35-51.53-6.73-75.81l83.46,26.2L345.73,113.225z" />
|
||||
<path style="fill:#13c9ca;" d="M393.49,219.465c-7.48,3.9-15.23,6.76-23.08,8.63c-17.7,4.21-35.91,3.38-52.74-1.91l26.47-84.29
|
||||
l3.32-10.59L393.49,219.465z" />
|
||||
<path style="fill:#a5a5a5;" d="M391.75,201.375l-46.02-88.15l-11.42-3.59l-83.46-26.2c7.63-24.29,24.51-45.66,48.85-58.37
|
||||
c2.55-1.33,5.12-2.54,7.73-3.62c22.27-9.33,46.35-9.93,68.09-3.1c24.29,7.62,45.66,24.5,58.37,48.85
|
||||
C459.3,115.885,440.44,175.955,391.75,201.375z" />
|
||||
<polyline style="fill:#FFFFFF;"
|
||||
points="226.383,168.765 40.652,168.765 40.652,354.496 226.383,354.496 226.383,168.765 " />
|
||||
<polyline style="fill:#2BE0C6;"
|
||||
points="93.6,254.001 57.602,254.001 57.602,343.996 93.6,343.996 93.6,254.001 " />
|
||||
<polyline style="fill:#ffbc58;"
|
||||
points="151.517,224.002 115.518,224.002 115.518,343.996 151.517,343.996 151.517,224.002 " />
|
||||
<polyline style="fill:#a5a5a5;"
|
||||
points="209.432,191.004 173.435,191.004 173.435,343.996 209.432,343.996 209.432,191.004 " />
|
||||
<polyline style="fill:#13c9ca;"
|
||||
points="242.83,325.765 242.83,454.765 0,454.765 0,325.765 242.83,325.765 " />
|
||||
<polyline style="fill:#F2F2F2;"
|
||||
points="15,439.765 15,340.765 227.826,340.765 227.826,439.765 15,439.765 " />
|
||||
<polyline style="fill:#a5a5a5;"
|
||||
points="108.064,430.978 87.408,408.6 78.664,420.466 71.9,415.483 86.68,395.426 106.349,416.734
|
||||
137.239,360.959 160.785,398.8 188.393,349.552 195.722,353.66 161.162,415.307 137.661,377.538 108.064,430.978 " />
|
||||
<rect x="26" y="357.765" style="fill:#999999;" width="27" height="11" />
|
||||
<rect x="26" y="384.765" style="fill:#999999;" width="27" height="11" />
|
||||
<rect x="26" y="411.765" style="fill:#999999;" width="27" height="11" />
|
||||
<polyline style="fill:#6EC6EB;" points="242.83,325.765 209.432,325.765 173.435,325.765 151.517,325.765 115.518,325.765
|
||||
93.6,325.765 92.88,325.765 97.451,340.765 227.826,340.765 227.826,439.765 127.619,439.765 132.19,454.765 242.83,454.765
|
||||
242.83,325.765 " />
|
||||
<polyline style="fill:#F6F6F6;" points="227.826,340.765 97.451,340.765 115.542,400.135 137.239,360.959 160.785,398.8
|
||||
188.393,349.552 195.722,353.66 161.162,415.307 137.661,377.538 118.951,411.32 127.619,439.765 227.826,439.765 227.826,340.765
|
||||
" />
|
||||
<polyline style="fill:#FDA589;" points="188.393,349.552 160.785,398.8 137.239,360.959 115.542,400.135 118.951,411.32
|
||||
137.661,377.538 161.162,415.307 195.722,353.66 188.393,349.552 " />
|
||||
<path style="fill:#CCCCCC;"
|
||||
d="M393.695,417.909l8.485-20.662l25.251,25.251c1.464,1.464,3.387,2.199,5.303,2.192
|
||||
c1.923,0,3.84-0.728,5.303-2.192c2.934-2.934,2.927-7.679,0-10.607l-25.251-25.251l20.669-8.492l-78.559-38.792L393.695,417.909z" />
|
||||
<path style="fill:#808080;" d="M393.695,417.909l8.485-20.662l25.251,25.251c1.464,1.464,3.387,2.199,5.303,2.192
|
||||
c1.923,0,3.84-0.728,5.303-2.192l-83.142-83.142L393.695,417.909z" />
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="single-item">
|
||||
<owl-carousel-o [options]="owlcarouselOptions">
|
||||
<ng-container *ngFor="let data of owlcarousel">
|
||||
<ng-template carouselSlide class="item">
|
||||
<div>
|
||||
<h3>{{data.title}}</h3>
|
||||
<p>{{data.desc}}</p>
|
||||
</div>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
</owl-carousel-o>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-7 p-0 card-right">
|
||||
<div class="card tab2-card">
|
||||
<div style="padding: 46px;" class="card-body">
|
||||
<ul ngbNav #nav="ngbNav" [(activeId)]="active" class="nav-tabs">
|
||||
<li [ngbNavItem]="1">
|
||||
<h3 style="color: lightcoral" ngbNavLink>Đăng nhập</h3>
|
||||
<ng-template ngbNavContent>
|
||||
<div class="login-img-box d-flex justify-content-center align-items-center">
|
||||
<img class="login-img"
|
||||
src="../../../../assets/images/dashboard/Logo web.png">
|
||||
</div>
|
||||
<div class="tab-pane fade active show" id="account" role="tabpanel"
|
||||
aria-labelledby="account-tab">
|
||||
<form [formGroup]="loginForm" class="form-horizontal auth-form"
|
||||
novalidate="">
|
||||
<div class="form-group">
|
||||
<input required="" name="login[username]" type="email"
|
||||
class="form-control" placeholder="Email" formControlName="email"
|
||||
id="exampleInputEmail1">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="form-control input-password-holder">
|
||||
<input formControlName="password" class="input-password"
|
||||
type="{{ showPassword ? 'text' : 'password' }}" #pwc
|
||||
placeholder="Xác nhận mật khẩu" />
|
||||
<span class="icon-holder-eye"
|
||||
(click)="showPassword = !showPassword">
|
||||
<i
|
||||
class="{{ showPassword ? 'fa fa-eye-slash' : 'fa fa-eye' }}"></i>
|
||||
</span>
|
||||
</div>
|
||||
<!-- <input required="" name="login[password]" type="password"
|
||||
class="form-control" placeholder="Password"
|
||||
formControlName="password"> -->
|
||||
</div>
|
||||
<div class="form-button d-flex justify-content-end">
|
||||
<button class="btn btn-primary w-100 mt-0" type="submit"
|
||||
(click)="onSignIn()">Đăng nhập</button>
|
||||
</div>
|
||||
<div class="form-terms mt-1">
|
||||
<div class="d-flex justify-content-end">
|
||||
<!-- <a routerLink="/reset-password" routerLinkActive="active" class="">Quên mật khẩu</a> -->
|
||||
<a [routerLink]="['/auth/send-email']" routerLinkActive="active"
|
||||
class="">Quên mật khẩu ?</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-center align-items-center mt-2">
|
||||
<p class="mb-0 text-secondary">Trở thành người bán hàng của Foodify?
|
||||
</p>
|
||||
<a class="ml-2" [routerLink]="['/auth', 'signup']">Đăng ký ngay</a>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</ng-template>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
<div [ngbNavOutlet]="nav" class="mt-2"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-template #error_modal>
|
||||
<div class="modal-body text-center">
|
||||
<p>Sai tên tài khoản hoặc mật khẩu. Vui lòng kiểm tra lại !</p>
|
||||
<button type="button" class="btn btn-primary" (click)="closeLayer1()">Tiếp tục</button>
|
||||
</div>
|
||||
</ng-template>
|
||||
@@ -0,0 +1,39 @@
|
||||
.backgound-food {
|
||||
background-image: url('../../../../assets/images/background-login.jpg');
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
z-index: -99;
|
||||
|
||||
|
||||
@media (max-width:768px) {
|
||||
.disable-pink {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.login-img-box {
|
||||
width: 100%;
|
||||
padding-bottom: 20px;
|
||||
|
||||
.login-img {
|
||||
max-width: 442px;
|
||||
}
|
||||
}
|
||||
|
||||
.input-password-holder {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
.input-password {
|
||||
border: none;
|
||||
width: 100%;
|
||||
}
|
||||
.icon-holder-eye {
|
||||
color: #999a9b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
|
||||
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
|
||||
import { FirebaseService } from "../../../shared/service/firebase.service";
|
||||
import { Router } from '@angular/router';
|
||||
import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal';
|
||||
|
||||
@Component({
|
||||
selector: 'app-login',
|
||||
templateUrl: './login.component.html',
|
||||
styleUrls: ['./login.component.scss']
|
||||
})
|
||||
export class LoginComponent implements OnInit {
|
||||
|
||||
public loginForm: UntypedFormGroup;
|
||||
public registerForm: UntypedFormGroup;
|
||||
public active = 1;
|
||||
|
||||
// Password
|
||||
showPassword = false;
|
||||
|
||||
//Modal
|
||||
@ViewChild('error_modal') errorModal: TemplateRef<any>
|
||||
layer1: BsModalRef;
|
||||
|
||||
constructor(private formBuilder: UntypedFormBuilder,
|
||||
private firebaseAuthService: FirebaseService,
|
||||
private modalService: BsModalService,
|
||||
private router: Router) {
|
||||
this.createLoginForm();
|
||||
this.createRegisterForm();
|
||||
}
|
||||
|
||||
owlcarousel = [
|
||||
{
|
||||
title: "Chào mừng đến với Foodify",
|
||||
desc: "Foodify - Một trong những ứng dụng đặt đồ ăn tốt nhất hiện nay, được phát triển bởi Pyramide team",
|
||||
},
|
||||
{
|
||||
title: "Foodify - xu hướng mới",
|
||||
desc: "Với mục đích tạo ra những sản phẩm tốt nhất cho người dùng, chúng mình đã quyết định sử dụng các công nghệ mới nhất vào Foodify",
|
||||
},
|
||||
{
|
||||
title: "Về Pyramide Team",
|
||||
desc: "Pyramide team là một nhóm sinh viên trường Đại học FPT, team nghiên cứu và phát triển sản phẩm theo công nghệ Angular và Spring Boot",
|
||||
}
|
||||
]
|
||||
owlcarouselOptions = {
|
||||
loop: true,
|
||||
items: 1,
|
||||
dots: true
|
||||
};
|
||||
|
||||
createLoginForm() {
|
||||
this.loginForm = this.formBuilder.group({
|
||||
email: [''],
|
||||
password: [''],
|
||||
});
|
||||
}
|
||||
|
||||
createRegisterForm() {
|
||||
this.registerForm = this.formBuilder.group({
|
||||
email: [''],
|
||||
password: [''],
|
||||
confirmPassword: [''],
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
|
||||
}
|
||||
|
||||
onSignUp() {
|
||||
this.firebaseAuthService.signUp(this.getSignUpEmail, this.getSignUpPassword);
|
||||
}
|
||||
|
||||
onSignIn() {
|
||||
this.firebaseAuthService.signIn(this.getSignInEmail, this.getSignInPassword).then((result) => {
|
||||
if (result) {
|
||||
|
||||
}
|
||||
else {
|
||||
this.layer1 = this.modalService.show(this.errorModal, { class: "modal-sm" });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
closeLayer1() {
|
||||
this.layer1.hide();
|
||||
}
|
||||
|
||||
get getSignUpEmail() {
|
||||
return this.registerForm.get('email').getRawValue();
|
||||
}
|
||||
|
||||
get getSignUpPassword() {
|
||||
return this.registerForm.get('password').getRawValue();
|
||||
}
|
||||
|
||||
get getSignInEmail() {
|
||||
return this.loginForm.get('email').getRawValue();
|
||||
}
|
||||
|
||||
get getSignInPassword() {
|
||||
return this.loginForm.get('password').getRawValue();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
<div class="page-wrapper">
|
||||
<div class="authentication-box backgound-food">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-5 p-0 card-left disable-pink">
|
||||
<div class="card bg-primary">
|
||||
<div class="svg-icon">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 468.52 468.52"
|
||||
style="enable-background: new 0 0 468.52 468.52" xml:space="preserve">
|
||||
<g>
|
||||
<path style="fill: #e6e6e6" d="M468.52,102.595v251.88c0,11.14-7.571,20.52-17.86,23.25c-1.98,0.531-4.06,0.81-6.2,0.81H38.58
|
||||
c-13.29,0-24.061-10.77-24.061-24.06v-251.88c0-13.29,10.771-24.06,24.061-24.06h405.88c2.14,0,4.22,0.28,6.2,0.81
|
||||
C460.949,82.075,468.52,91.455,468.52,102.595" />
|
||||
<path style="fill: #b3b3b3" d="M468.518,102.591v23.94h-454v-23.94c0-13.29,10.771-24.06,24.06-24.06h405.88
|
||||
C457.747,78.532,468.518,89.302,468.518,102.591" />
|
||||
<rect x="42.099" y="141.002" style="fill: #999999" width="118.901" height="16.532" />
|
||||
<polyline style="fill: #ffffff"
|
||||
points="442.383,222.765 256.652,222.765 256.652,354.496 442.383,354.496 442.383,222.765 " />
|
||||
<polyline style="fill: #13c9ca"
|
||||
points="434.552,329.733 265.552,329.733 265.552,346.265 434.552,346.265 434.552,329.733 " />
|
||||
<polyline style="fill: #a5a5a5"
|
||||
points="286.552,297.744 265.552,297.744 265.552,314.276 286.552,314.276 286.552,297.744 " />
|
||||
<polyline style="fill: #ffbc58"
|
||||
points="350.552,265.754 265.552,265.754 265.552,282.286 350.552,282.286 350.552,265.754 " />
|
||||
<polyline style="fill: #999999"
|
||||
points="411.552,233.765 265.552,233.765 265.552,250.297 411.552,250.297 411.552,233.765 " />
|
||||
<circle style="fill: #a5a5a5" cx="47.517" cy="102.532" r="15" />
|
||||
<circle style="fill: #ffbc58" cx="87.517" cy="102.532" r="15" />
|
||||
<path style="fill: #eeeeee" d="M463.696,88.139c3.027,4.024,4.822,9.029,4.822,14.453v23.94h-23.321
|
||||
c0.04,35.899-19.42,70.584-53.444,88.347c-2.102,0.921-4.223,1.779-6.365,2.574l2.774,5.313h54.222v131.731H298.563l7.326,24.038
|
||||
h138.57c2.14,0,4.22-0.28,6.2-0.81c10.29-2.73,17.86-12.11,17.86-23.25v-251.88C468.52,97.17,466.725,92.164,463.696,88.139
|
||||
M463.657,88.088c0.012,0.016,0.023,0.031,0.036,0.047C463.681,88.12,463.669,88.103,463.657,88.088 M463.621,88.04
|
||||
c0.008,0.01,0.015,0.02,0.023,0.03C463.636,88.06,463.629,88.05,463.621,88.04 M463.59,87.999c0.003,0.004,0.006,0.008,0.009,0.012
|
||||
C463.596,88.007,463.593,88.003,463.59,87.999" />
|
||||
<path style="fill: #cbcbcb" d="M444.46,78.535h-11.739c0.396,0.716,0.784,1.437,1.165,2.167c7.655,14.662,11.293,30.36,11.31,45.83
|
||||
h23.321v-23.94c0-5.424-1.795-10.429-4.822-14.453l0,0c-0.001-0.001-0.002-0.002-0.003-0.003l0,0
|
||||
c-0.012-0.016-0.023-0.031-0.036-0.047l0,0c-0.005-0.006-0.009-0.012-0.014-0.018l0,0c-0.008-0.01-0.015-0.02-0.023-0.03l0,0
|
||||
c-0.007-0.01-0.014-0.019-0.022-0.029l0,0c-0.003-0.004-0.006-0.008-0.009-0.012l0,0c-3.187-4.171-7.708-7.269-12.93-8.654
|
||||
C448.68,78.815,446.6,78.535,444.46,78.535" />
|
||||
<path style="fill: #ffffff" d="M442.383,222.765h-54.222l5.326,10.202c-0.519,0.271-1.04,0.537-1.561,0.798h19.626v16.532H266.807
|
||||
l4.711,15.457h79.034v16.532h-73.996l4.711,15.458h5.285v16.532h-0.246l4.711,15.457h143.536v16.532H296.055l2.509,8.231h143.819
|
||||
V222.765" />
|
||||
<polyline style="fill: #6ec6eb"
|
||||
points="434.552,329.733 291.016,329.733 296.055,346.265 434.552,346.265 434.552,329.733 " />
|
||||
<polyline style="fill: #fda589"
|
||||
points="286.552,297.744 281.267,297.744 286.306,314.276 286.552,314.276 286.552,297.744 " />
|
||||
<polyline style="fill: #fbe98e"
|
||||
points="350.552,265.754 271.518,265.754 276.556,282.286 350.552,282.286 350.552,265.754 " />
|
||||
<path style="fill: #eeeeee" d="M246.265,126.531h-17.178l29.329,96.234h62.908c-1.465-0.282-2.926-0.591-4.384-0.929l-1.001-0.232
|
||||
c-24.282-7.625-45.651-24.51-58.362-48.855C249.857,157.962,246.221,142.128,246.265,126.531" />
|
||||
<path style="fill: #cbcbcb" d="M258.73,78.535h-44.27l14.628,47.996h17.178c0.028-10.08,1.594-20.062,4.587-29.594
|
||||
C252.852,90.569,255.489,84.4,258.73,78.535" />
|
||||
<path style="fill: #ffffff" d="M321.324,222.765h-62.908l7.136,23.415v-12.415h53.983l3.362-10.708
|
||||
C322.373,222.963,321.848,222.866,321.324,222.765" />
|
||||
<path style="fill: #bababa" d="M411.552,233.765h-19.626c-14.25,7.129-29.421,10.514-44.383,10.514
|
||||
c-10.173,0-20.251-1.566-29.869-4.586l1.861-5.928h-53.983v12.415l1.255,4.117h144.745V233.765" />
|
||||
<path style="fill: #cecece"
|
||||
d="M385.387,217.453c-6.196,2.3-12.551,4.073-18.994,5.313h21.767L385.387,217.453" />
|
||||
<path style="fill: #dbdbdb"
|
||||
d="M388.161,222.765h-21.767c-7.428,1.428-14.973,2.147-22.536,2.147
|
||||
c-6.999,0-14.015-0.616-20.959-1.855l-3.362,10.708h72.391c0.521-0.261,1.042-0.527,1.561-0.798L388.161,222.765" />
|
||||
<path style="fill: #a4a4a4" d="M391.926,233.765h-72.391l-1.861,5.928c9.618,3.02,19.696,4.586,29.869,4.586
|
||||
C362.505,244.279,377.677,240.894,391.926,233.765" />
|
||||
<path style="fill: #dbdbdb" d="M345.64,27.261c-15.507,0-31.24,3.637-45.936,11.309c-17.955,9.374-31.855,23.466-40.973,39.961
|
||||
h173.987c-12.828-23.18-33.641-39.288-57.199-46.682C365.898,28.829,355.817,27.261,345.64,27.261" />
|
||||
<polyline style="fill: #9f9f9f"
|
||||
points="432.719,78.532 258.732,78.532 258.73,78.535 432.721,78.535 432.719,78.532 " />
|
||||
<path style="fill: #cecece"
|
||||
d="M445.196,126.531H246.265c-0.044,15.597,3.592,31.43,11.312,46.218
|
||||
c12.711,24.345,34.08,41.23,58.362,48.855l1.001,0.232c1.458,0.338,2.919,0.647,4.384,0.929h45.069
|
||||
c6.443-1.239,12.797-3.012,18.994-5.313c2.142-0.795,4.263-1.653,6.365-2.574C425.776,197.115,445.237,162.431,445.196,126.531" />
|
||||
<path style="fill: #b2b2b2" d="M432.721,78.535H258.73c-3.241,5.865-5.878,12.033-7.878,18.402
|
||||
c-2.993,9.532-4.559,19.515-4.587,29.594h198.931c-0.017-15.469-3.656-31.168-11.31-45.83
|
||||
C433.505,79.972,433.117,79.251,432.721,78.535" />
|
||||
<path style="fill: #dbdbdb" d="M366.393,222.765h-45.069c0.524,0.101,1.049,0.198,1.574,0.292
|
||||
c6.945,1.239,13.96,1.855,20.959,1.855C351.42,224.912,358.965,224.193,366.393,222.765" />
|
||||
<path style="fill: #ffbc58" d="M345.73,113.225l-5.24,16.69l-24.55,78.18c-24.28-7.62-45.65-24.51-58.36-48.85
|
||||
c-12.71-24.35-14.35-51.53-6.73-75.81l83.46,26.2L345.73,113.225z" />
|
||||
<path style="fill: #13c9ca" d="M393.49,219.465c-7.48,3.9-15.23,6.76-23.08,8.63c-17.7,4.21-35.91,3.38-52.74-1.91l26.47-84.29
|
||||
l3.32-10.59L393.49,219.465z" />
|
||||
<path style="fill: #a5a5a5" d="M391.75,201.375l-46.02-88.15l-11.42-3.59l-83.46-26.2c7.63-24.29,24.51-45.66,48.85-58.37
|
||||
c2.55-1.33,5.12-2.54,7.73-3.62c22.27-9.33,46.35-9.93,68.09-3.1c24.29,7.62,45.66,24.5,58.37,48.85
|
||||
C459.3,115.885,440.44,175.955,391.75,201.375z" />
|
||||
<polyline style="fill: #ffffff"
|
||||
points="226.383,168.765 40.652,168.765 40.652,354.496 226.383,354.496 226.383,168.765 " />
|
||||
<polyline style="fill: #2be0c6"
|
||||
points="93.6,254.001 57.602,254.001 57.602,343.996 93.6,343.996 93.6,254.001 " />
|
||||
<polyline style="fill: #ffbc58"
|
||||
points="151.517,224.002 115.518,224.002 115.518,343.996 151.517,343.996 151.517,224.002 " />
|
||||
<polyline style="fill: #a5a5a5"
|
||||
points="209.432,191.004 173.435,191.004 173.435,343.996 209.432,343.996 209.432,191.004 " />
|
||||
<polyline style="fill: #13c9ca"
|
||||
points="242.83,325.765 242.83,454.765 0,454.765 0,325.765 242.83,325.765 " />
|
||||
<polyline style="fill: #f2f2f2"
|
||||
points="15,439.765 15,340.765 227.826,340.765 227.826,439.765 15,439.765 " />
|
||||
<polyline style="fill: #a5a5a5"
|
||||
points="108.064,430.978 87.408,408.6 78.664,420.466 71.9,415.483 86.68,395.426 106.349,416.734
|
||||
137.239,360.959 160.785,398.8 188.393,349.552 195.722,353.66 161.162,415.307 137.661,377.538 108.064,430.978 " />
|
||||
<rect x="26" y="357.765" style="fill: #999999" width="27" height="11" />
|
||||
<rect x="26" y="384.765" style="fill: #999999" width="27" height="11" />
|
||||
<rect x="26" y="411.765" style="fill: #999999" width="27" height="11" />
|
||||
<polyline style="fill: #6ec6eb" points="242.83,325.765 209.432,325.765 173.435,325.765 151.517,325.765 115.518,325.765
|
||||
93.6,325.765 92.88,325.765 97.451,340.765 227.826,340.765 227.826,439.765 127.619,439.765 132.19,454.765 242.83,454.765
|
||||
242.83,325.765 " />
|
||||
<polyline style="fill: #f6f6f6" points="227.826,340.765 97.451,340.765 115.542,400.135 137.239,360.959 160.785,398.8
|
||||
188.393,349.552 195.722,353.66 161.162,415.307 137.661,377.538 118.951,411.32 127.619,439.765 227.826,439.765 227.826,340.765
|
||||
" />
|
||||
<polyline style="fill: #fda589" points="188.393,349.552 160.785,398.8 137.239,360.959 115.542,400.135 118.951,411.32
|
||||
137.661,377.538 161.162,415.307 195.722,353.66 188.393,349.552 " />
|
||||
<path style="fill: #cccccc"
|
||||
d="M393.695,417.909l8.485-20.662l25.251,25.251c1.464,1.464,3.387,2.199,5.303,2.192
|
||||
c1.923,0,3.84-0.728,5.303-2.192c2.934-2.934,2.927-7.679,0-10.607l-25.251-25.251l20.669-8.492l-78.559-38.792L393.695,417.909z" />
|
||||
<path style="fill: #808080" d="M393.695,417.909l8.485-20.662l25.251,25.251c1.464,1.464,3.387,2.199,5.303,2.192
|
||||
c1.923,0,3.84-0.728,5.303-2.192l-83.142-83.142L393.695,417.909z" />
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="single-item">
|
||||
<owl-carousel-o [options]="owlcarouselOptions">
|
||||
<ng-container *ngFor="let data of owlcarousel">
|
||||
<ng-template carouselSlide class="item">
|
||||
<div>
|
||||
<h3>{{ data.title }}</h3>
|
||||
<p>{{ data.desc }}</p>
|
||||
</div>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
</owl-carousel-o>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-7 p-0 card-right">
|
||||
<div class="card tab2-card">
|
||||
<div class="card-body">
|
||||
<ul ngbNav #nav="ngbNav" [(activeId)]="active" class="nav-tabs">
|
||||
<li [ngbNavItem]="1">
|
||||
<h3 style="color: lightcoral" ngbNavLink>Thay đổi mật khẩu mới</h3>
|
||||
<ng-template ngbNavContent>
|
||||
|
||||
<div class="reset-img-box d-flex justify-content-center align-items-center">
|
||||
<img class="reset-img" src="../../../../assets/images/dashboard/reset-password.png">
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade active show" id="account" role="tabpanel" aria-labelledby="account-tab">
|
||||
<form [formGroup]="resetPasswordForm" class="form-horizontal auth-form" novalidate="">
|
||||
<div class="form-group">
|
||||
<div class="form-control input-password-holder">
|
||||
<input formControlName="password" class="input-password"
|
||||
type="{{ showPassword ? 'text' : 'password' }}" placeholder="Mật khẩu mới" />
|
||||
<span class="icon-holder-eye" (click)="showPassword = !showPassword">
|
||||
<i class="{{ showPassword ? 'fa fa-eye-slash' : 'fa fa-eye' }}"></i>
|
||||
</span>
|
||||
</div>
|
||||
<div *ngIf="password?.invalid && (password?.dirty || password?.touched)"
|
||||
class="alert alert-danger mt-1">
|
||||
<div *ngIf="password?.errors?.['required']">Vui lòng không được bỏ trống mật khẩu.</div>
|
||||
<div *ngIf="password?.errors?.['pattern']">
|
||||
Mật khẩu phải chứa ít nhất 8 ký tự, trong đó gồm một ký tự số, một chữ hoa, một chữ thường
|
||||
và một ký tự đặc biệt.
|
||||
<br />
|
||||
Mật khẩu không được chứa khoảng trắng.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="form-control input-password-holder">
|
||||
<input formControlName="confirmPassword" class="input-password"
|
||||
type="{{ showPassword ? 'text' : 'password' }}" #pwc placeholder="Xác nhận mật khẩu" />
|
||||
<span class="icon-holder-eye" (click)="showPassword = !showPassword">
|
||||
<i class="{{ showPassword ? 'fa fa-eye-slash' : 'fa fa-eye' }}"></i>
|
||||
</span>
|
||||
</div>
|
||||
<div *ngIf="
|
||||
confirmPassword?.invalid &&
|
||||
(confirmPassword?.dirty || confirmPassword?.touched)
|
||||
" class="alert alert-danger mt-1">
|
||||
<div *ngIf="confirmPassword?.errors?.['required']">Vui lòng xác nhận mật khẩu.</div>
|
||||
<div *ngIf="confirmPassword?.errors?.['pattern']">
|
||||
Mật khẩu phải chứa ít nhất 8 ký tự, trong đó gồm một ký tự số, một chữ hoa, một chữ thường
|
||||
và một ký tự đặc biệt.
|
||||
<br />
|
||||
Mật khẩu không được chứa khoảng trắng.
|
||||
</div>
|
||||
<div *ngIf="confirmPassword?.errors?.['confirmedValidator']">
|
||||
Mật khẩu xác nhận phải giống với mật khẩu đã nhập
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-button">
|
||||
<button class="btn btn-primary" type="submit"
|
||||
(click)="changePassword(changePasswordCompleted)">Thay đổi</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</ng-template>
|
||||
</li>
|
||||
</ul>
|
||||
<div [ngbNavOutlet]="nav" class="mt-2"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-template #changePasswordCompleted>
|
||||
<div class="modal-body text-center">
|
||||
<p>Thay đổi mật khẩu thành công</p>
|
||||
<button type="button" class="btn btn-primary" (click)="backToLogin()"> Đăng nhập ngay
|
||||
</button>
|
||||
</div>
|
||||
</ng-template>
|
||||
@@ -0,0 +1,39 @@
|
||||
.backgound-food {
|
||||
background-image: url('../../../../assets/images/background-login.jpg');
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
z-index: -99;
|
||||
|
||||
@media (max-width:768px) {
|
||||
.disable-pink {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.reset-img-box {
|
||||
.reset-img {
|
||||
max-width: 265px;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.input-password-holder {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
.input-password {
|
||||
border: none;
|
||||
width: 100%;
|
||||
}
|
||||
.icon-holder-eye {
|
||||
color: #999a9b;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
|
||||
import { FormControl, FormGroup, UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
|
||||
import { FirebaseService } from "../../../shared/service/firebase.service";
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Validation } from 'src/app/constants/Validation';
|
||||
import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal';
|
||||
|
||||
@Component({
|
||||
selector: "app-reset-password",
|
||||
templateUrl: "./reset-password.component.html",
|
||||
styleUrls: ["./reset-password.component.scss"],
|
||||
})
|
||||
export class ResetPasswordComponent {
|
||||
public resetPasswordForm: FormGroup
|
||||
public active = 1;
|
||||
|
||||
// Password
|
||||
action: string = '';
|
||||
oobCode: string = '';
|
||||
showPassword = false;
|
||||
|
||||
//Modal
|
||||
layer1: BsModalRef;
|
||||
|
||||
|
||||
constructor(
|
||||
private formBuilder: UntypedFormBuilder,
|
||||
private activatedRoute: ActivatedRoute,
|
||||
private firebaseService: FirebaseService,
|
||||
private modalService: BsModalService,
|
||||
private router: Router
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
owlcarousel = [
|
||||
{
|
||||
title: "Chào mừng đến với Foodify",
|
||||
desc: "Foodify - Một trong những ứng dụng đặt đồ ăn tốt nhất hiện nay, được phát triển bởi Pyramide team",
|
||||
},
|
||||
{
|
||||
title: "Foodify - xu hướng mới",
|
||||
desc: "Với mục đích tạo ra những sản phẩm tốt nhất cho người dùng, chúng mình đã quyết định sử dụng các công nghệ mới nhất vào Foodify",
|
||||
},
|
||||
{
|
||||
title: "Về Pyramide Team",
|
||||
desc: "Pyramide team là một nhóm sinh viên trường Đại học FPT, team nghiên cứu và phát triển sản phẩm theo công nghệ Angular và Spring Boot",
|
||||
},
|
||||
];
|
||||
owlcarouselOptions = {
|
||||
loop: true,
|
||||
items: 1,
|
||||
dots: true,
|
||||
};
|
||||
|
||||
ngOnInit() {
|
||||
//Get Token from link
|
||||
this.oobCode = this.activatedRoute.snapshot.queryParamMap.get('oobCode');
|
||||
this.action = this.activatedRoute.snapshot.queryParamMap.get('mode');
|
||||
|
||||
if (this.action == 'verifyEmail') {
|
||||
this.firebaseService.confirmVerifyEmail(this.oobCode)
|
||||
this.router.navigate(['/auth/email-verified'])
|
||||
}
|
||||
|
||||
if (this.oobCode) {
|
||||
this.resetPasswordForm = this.formBuilder.group({
|
||||
password: new FormControl("", [Validators.required, Validators.pattern(Validation.Regex.Password)]),
|
||||
confirmPassword: new FormControl("", [Validators.required, Validators.pattern(Validation.Regex.Password)]),
|
||||
},
|
||||
{
|
||||
validator: this.ConfirmedValidator("password", "confirmPassword"),
|
||||
})
|
||||
}
|
||||
else {
|
||||
this.router.navigate(['/auth/forbidden']);
|
||||
}
|
||||
}
|
||||
|
||||
//Change password
|
||||
changePassword(success: TemplateRef<any>) {
|
||||
if (this.resetPasswordForm.invalid) {
|
||||
this.resetPasswordForm.markAllAsTouched();
|
||||
return;
|
||||
}
|
||||
|
||||
this.firebaseService.confirmPasswordReset(this.oobCode, this.password.value);
|
||||
this.layer1 = this.modalService.show(success, { class: 'modal-sm' })
|
||||
}
|
||||
|
||||
backToLogin() {
|
||||
this.layer1.hide();
|
||||
this.router.navigate(['/auth/login']);
|
||||
}
|
||||
|
||||
// Validation for password and confirm password
|
||||
ConfirmedValidator(controlName: string, matchingControlName: string) {
|
||||
return (formGroup: FormGroup) => {
|
||||
const control = formGroup.controls[controlName];
|
||||
const matchingControl = formGroup.controls[matchingControlName];
|
||||
if (matchingControl.errors && !matchingControl.errors.confirmedValidator) {
|
||||
return;
|
||||
}
|
||||
if (control.value !== matchingControl.value) {
|
||||
matchingControl.setErrors({ confirmedValidator: true });
|
||||
} else {
|
||||
matchingControl.setErrors(null);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
get password() {
|
||||
return this.resetPasswordForm.get("password");
|
||||
}
|
||||
|
||||
get confirmPassword() {
|
||||
return this.resetPasswordForm.get("confirmPassword");
|
||||
}
|
||||
|
||||
// onSignUp() {
|
||||
// this.firebaseAuthService.signUp(this.getSignUpEmail, this.getSignUpPassword);
|
||||
// }
|
||||
|
||||
// onSignIn() {
|
||||
// this.firebaseAuthService.signIn(this.getSignInEmail, this.getSignInPassword);
|
||||
// }
|
||||
|
||||
|
||||
// get getSignUpPassword() {
|
||||
// return this.registerForm.get("password").getRawValue();
|
||||
// }
|
||||
|
||||
// get getSignInEmail() {
|
||||
// return this.loginForm.get("email").getRawValue();
|
||||
// }
|
||||
|
||||
// get getSignInPassword() {
|
||||
// return this.loginForm.get("password").getRawValue();
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
<div class="page-wrapper">
|
||||
<div class="authentication-box backgound-food">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-5 p-0 card-left disable-pink">
|
||||
<div class="card bg-primary">
|
||||
<div class="svg-icon">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 468.52 468.52"
|
||||
style="enable-background: new 0 0 468.52 468.52" xml:space="preserve">
|
||||
<g>
|
||||
<path style="fill: #e6e6e6" d="M468.52,102.595v251.88c0,11.14-7.571,20.52-17.86,23.25c-1.98,0.531-4.06,0.81-6.2,0.81H38.58
|
||||
c-13.29,0-24.061-10.77-24.061-24.06v-251.88c0-13.29,10.771-24.06,24.061-24.06h405.88c2.14,0,4.22,0.28,6.2,0.81
|
||||
C460.949,82.075,468.52,91.455,468.52,102.595" />
|
||||
<path style="fill: #b3b3b3" d="M468.518,102.591v23.94h-454v-23.94c0-13.29,10.771-24.06,24.06-24.06h405.88
|
||||
C457.747,78.532,468.518,89.302,468.518,102.591" />
|
||||
<rect x="42.099" y="141.002" style="fill: #999999" width="118.901" height="16.532" />
|
||||
<polyline style="fill: #ffffff"
|
||||
points="442.383,222.765 256.652,222.765 256.652,354.496 442.383,354.496 442.383,222.765 " />
|
||||
<polyline style="fill: #13c9ca"
|
||||
points="434.552,329.733 265.552,329.733 265.552,346.265 434.552,346.265 434.552,329.733 " />
|
||||
<polyline style="fill: #a5a5a5"
|
||||
points="286.552,297.744 265.552,297.744 265.552,314.276 286.552,314.276 286.552,297.744 " />
|
||||
<polyline style="fill: #ffbc58"
|
||||
points="350.552,265.754 265.552,265.754 265.552,282.286 350.552,282.286 350.552,265.754 " />
|
||||
<polyline style="fill: #999999"
|
||||
points="411.552,233.765 265.552,233.765 265.552,250.297 411.552,250.297 411.552,233.765 " />
|
||||
<circle style="fill: #a5a5a5" cx="47.517" cy="102.532" r="15" />
|
||||
<circle style="fill: #ffbc58" cx="87.517" cy="102.532" r="15" />
|
||||
<path style="fill: #eeeeee" d="M463.696,88.139c3.027,4.024,4.822,9.029,4.822,14.453v23.94h-23.321
|
||||
c0.04,35.899-19.42,70.584-53.444,88.347c-2.102,0.921-4.223,1.779-6.365,2.574l2.774,5.313h54.222v131.731H298.563l7.326,24.038
|
||||
h138.57c2.14,0,4.22-0.28,6.2-0.81c10.29-2.73,17.86-12.11,17.86-23.25v-251.88C468.52,97.17,466.725,92.164,463.696,88.139
|
||||
M463.657,88.088c0.012,0.016,0.023,0.031,0.036,0.047C463.681,88.12,463.669,88.103,463.657,88.088 M463.621,88.04
|
||||
c0.008,0.01,0.015,0.02,0.023,0.03C463.636,88.06,463.629,88.05,463.621,88.04 M463.59,87.999c0.003,0.004,0.006,0.008,0.009,0.012
|
||||
C463.596,88.007,463.593,88.003,463.59,87.999" />
|
||||
<path style="fill: #cbcbcb" d="M444.46,78.535h-11.739c0.396,0.716,0.784,1.437,1.165,2.167c7.655,14.662,11.293,30.36,11.31,45.83
|
||||
h23.321v-23.94c0-5.424-1.795-10.429-4.822-14.453l0,0c-0.001-0.001-0.002-0.002-0.003-0.003l0,0
|
||||
c-0.012-0.016-0.023-0.031-0.036-0.047l0,0c-0.005-0.006-0.009-0.012-0.014-0.018l0,0c-0.008-0.01-0.015-0.02-0.023-0.03l0,0
|
||||
c-0.007-0.01-0.014-0.019-0.022-0.029l0,0c-0.003-0.004-0.006-0.008-0.009-0.012l0,0c-3.187-4.171-7.708-7.269-12.93-8.654
|
||||
C448.68,78.815,446.6,78.535,444.46,78.535" />
|
||||
<path style="fill: #ffffff" d="M442.383,222.765h-54.222l5.326,10.202c-0.519,0.271-1.04,0.537-1.561,0.798h19.626v16.532H266.807
|
||||
l4.711,15.457h79.034v16.532h-73.996l4.711,15.458h5.285v16.532h-0.246l4.711,15.457h143.536v16.532H296.055l2.509,8.231h143.819
|
||||
V222.765" />
|
||||
<polyline style="fill: #6ec6eb"
|
||||
points="434.552,329.733 291.016,329.733 296.055,346.265 434.552,346.265 434.552,329.733 " />
|
||||
<polyline style="fill: #fda589"
|
||||
points="286.552,297.744 281.267,297.744 286.306,314.276 286.552,314.276 286.552,297.744 " />
|
||||
<polyline style="fill: #fbe98e"
|
||||
points="350.552,265.754 271.518,265.754 276.556,282.286 350.552,282.286 350.552,265.754 " />
|
||||
<path style="fill: #eeeeee" d="M246.265,126.531h-17.178l29.329,96.234h62.908c-1.465-0.282-2.926-0.591-4.384-0.929l-1.001-0.232
|
||||
c-24.282-7.625-45.651-24.51-58.362-48.855C249.857,157.962,246.221,142.128,246.265,126.531" />
|
||||
<path style="fill: #cbcbcb" d="M258.73,78.535h-44.27l14.628,47.996h17.178c0.028-10.08,1.594-20.062,4.587-29.594
|
||||
C252.852,90.569,255.489,84.4,258.73,78.535" />
|
||||
<path style="fill: #ffffff" d="M321.324,222.765h-62.908l7.136,23.415v-12.415h53.983l3.362-10.708
|
||||
C322.373,222.963,321.848,222.866,321.324,222.765" />
|
||||
<path style="fill: #bababa" d="M411.552,233.765h-19.626c-14.25,7.129-29.421,10.514-44.383,10.514
|
||||
c-10.173,0-20.251-1.566-29.869-4.586l1.861-5.928h-53.983v12.415l1.255,4.117h144.745V233.765" />
|
||||
<path style="fill: #cecece"
|
||||
d="M385.387,217.453c-6.196,2.3-12.551,4.073-18.994,5.313h21.767L385.387,217.453" />
|
||||
<path style="fill: #dbdbdb"
|
||||
d="M388.161,222.765h-21.767c-7.428,1.428-14.973,2.147-22.536,2.147
|
||||
c-6.999,0-14.015-0.616-20.959-1.855l-3.362,10.708h72.391c0.521-0.261,1.042-0.527,1.561-0.798L388.161,222.765" />
|
||||
<path style="fill: #a4a4a4" d="M391.926,233.765h-72.391l-1.861,5.928c9.618,3.02,19.696,4.586,29.869,4.586
|
||||
C362.505,244.279,377.677,240.894,391.926,233.765" />
|
||||
<path style="fill: #dbdbdb" d="M345.64,27.261c-15.507,0-31.24,3.637-45.936,11.309c-17.955,9.374-31.855,23.466-40.973,39.961
|
||||
h173.987c-12.828-23.18-33.641-39.288-57.199-46.682C365.898,28.829,355.817,27.261,345.64,27.261" />
|
||||
<polyline style="fill: #9f9f9f"
|
||||
points="432.719,78.532 258.732,78.532 258.73,78.535 432.721,78.535 432.719,78.532 " />
|
||||
<path style="fill: #cecece"
|
||||
d="M445.196,126.531H246.265c-0.044,15.597,3.592,31.43,11.312,46.218
|
||||
c12.711,24.345,34.08,41.23,58.362,48.855l1.001,0.232c1.458,0.338,2.919,0.647,4.384,0.929h45.069
|
||||
c6.443-1.239,12.797-3.012,18.994-5.313c2.142-0.795,4.263-1.653,6.365-2.574C425.776,197.115,445.237,162.431,445.196,126.531" />
|
||||
<path style="fill: #b2b2b2" d="M432.721,78.535H258.73c-3.241,5.865-5.878,12.033-7.878,18.402
|
||||
c-2.993,9.532-4.559,19.515-4.587,29.594h198.931c-0.017-15.469-3.656-31.168-11.31-45.83
|
||||
C433.505,79.972,433.117,79.251,432.721,78.535" />
|
||||
<path style="fill: #dbdbdb" d="M366.393,222.765h-45.069c0.524,0.101,1.049,0.198,1.574,0.292
|
||||
c6.945,1.239,13.96,1.855,20.959,1.855C351.42,224.912,358.965,224.193,366.393,222.765" />
|
||||
<path style="fill: #ffbc58" d="M345.73,113.225l-5.24,16.69l-24.55,78.18c-24.28-7.62-45.65-24.51-58.36-48.85
|
||||
c-12.71-24.35-14.35-51.53-6.73-75.81l83.46,26.2L345.73,113.225z" />
|
||||
<path style="fill: #13c9ca" d="M393.49,219.465c-7.48,3.9-15.23,6.76-23.08,8.63c-17.7,4.21-35.91,3.38-52.74-1.91l26.47-84.29
|
||||
l3.32-10.59L393.49,219.465z" />
|
||||
<path style="fill: #a5a5a5" d="M391.75,201.375l-46.02-88.15l-11.42-3.59l-83.46-26.2c7.63-24.29,24.51-45.66,48.85-58.37
|
||||
c2.55-1.33,5.12-2.54,7.73-3.62c22.27-9.33,46.35-9.93,68.09-3.1c24.29,7.62,45.66,24.5,58.37,48.85
|
||||
C459.3,115.885,440.44,175.955,391.75,201.375z" />
|
||||
<polyline style="fill: #ffffff"
|
||||
points="226.383,168.765 40.652,168.765 40.652,354.496 226.383,354.496 226.383,168.765 " />
|
||||
<polyline style="fill: #2be0c6"
|
||||
points="93.6,254.001 57.602,254.001 57.602,343.996 93.6,343.996 93.6,254.001 " />
|
||||
<polyline style="fill: #ffbc58"
|
||||
points="151.517,224.002 115.518,224.002 115.518,343.996 151.517,343.996 151.517,224.002 " />
|
||||
<polyline style="fill: #a5a5a5"
|
||||
points="209.432,191.004 173.435,191.004 173.435,343.996 209.432,343.996 209.432,191.004 " />
|
||||
<polyline style="fill: #13c9ca"
|
||||
points="242.83,325.765 242.83,454.765 0,454.765 0,325.765 242.83,325.765 " />
|
||||
<polyline style="fill: #f2f2f2"
|
||||
points="15,439.765 15,340.765 227.826,340.765 227.826,439.765 15,439.765 " />
|
||||
<polyline style="fill: #a5a5a5"
|
||||
points="108.064,430.978 87.408,408.6 78.664,420.466 71.9,415.483 86.68,395.426 106.349,416.734
|
||||
137.239,360.959 160.785,398.8 188.393,349.552 195.722,353.66 161.162,415.307 137.661,377.538 108.064,430.978 " />
|
||||
<rect x="26" y="357.765" style="fill: #999999" width="27" height="11" />
|
||||
<rect x="26" y="384.765" style="fill: #999999" width="27" height="11" />
|
||||
<rect x="26" y="411.765" style="fill: #999999" width="27" height="11" />
|
||||
<polyline style="fill: #6ec6eb" points="242.83,325.765 209.432,325.765 173.435,325.765 151.517,325.765 115.518,325.765
|
||||
93.6,325.765 92.88,325.765 97.451,340.765 227.826,340.765 227.826,439.765 127.619,439.765 132.19,454.765 242.83,454.765
|
||||
242.83,325.765 " />
|
||||
<polyline style="fill: #f6f6f6" points="227.826,340.765 97.451,340.765 115.542,400.135 137.239,360.959 160.785,398.8
|
||||
188.393,349.552 195.722,353.66 161.162,415.307 137.661,377.538 118.951,411.32 127.619,439.765 227.826,439.765 227.826,340.765
|
||||
" />
|
||||
<polyline style="fill: #fda589" points="188.393,349.552 160.785,398.8 137.239,360.959 115.542,400.135 118.951,411.32
|
||||
137.661,377.538 161.162,415.307 195.722,353.66 188.393,349.552 " />
|
||||
<path style="fill: #cccccc"
|
||||
d="M393.695,417.909l8.485-20.662l25.251,25.251c1.464,1.464,3.387,2.199,5.303,2.192
|
||||
c1.923,0,3.84-0.728,5.303-2.192c2.934-2.934,2.927-7.679,0-10.607l-25.251-25.251l20.669-8.492l-78.559-38.792L393.695,417.909z" />
|
||||
<path style="fill: #808080" d="M393.695,417.909l8.485-20.662l25.251,25.251c1.464,1.464,3.387,2.199,5.303,2.192
|
||||
c1.923,0,3.84-0.728,5.303-2.192l-83.142-83.142L393.695,417.909z" />
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="single-item">
|
||||
<owl-carousel-o [options]="owlcarouselOptions">
|
||||
<ng-container *ngFor="let data of owlcarousel">
|
||||
<ng-template carouselSlide class="item">
|
||||
<div>
|
||||
<h3>{{ data.title }}</h3>
|
||||
<p>{{ data.desc }}</p>
|
||||
</div>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
</owl-carousel-o>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-7 p-0 card-right">
|
||||
<div class="card tab2-card">
|
||||
<div class="card-body">
|
||||
<ul ngbNav #nav="ngbNav" [(activeId)]="active" class="nav-tabs">
|
||||
<li [ngbNavItem]="1">
|
||||
<h3 style="color: lightcoral" ngbNavLink>Quên mật khẩu</h3>
|
||||
<ng-template ngbNavContent>
|
||||
|
||||
<div class="email-img-box d-flex justify-content-center align-items-center">
|
||||
<img class="email-img" src="../../../../assets/images/dashboard/email.png">
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade active show" id="account" role="tabpanel" aria-labelledby="account-tab">
|
||||
<form [formGroup]="sendEmailForm" class="form-horizontal auth-form" novalidate="">
|
||||
<div class="form-group d-flex justify-content-center align-items-center ">
|
||||
<i class="fa fa-envelope-o" aria-hidden="true"></i>
|
||||
<input type="email" class="form-control" placeholder="Vui lòng nhập Email"
|
||||
formControlName="email" />
|
||||
</div>
|
||||
<div *ngIf="email?.invalid && (email?.dirty || email?.touched)" class="alert alert-danger">
|
||||
<div *ngIf="email?.errors?.['required']">Vui lòng không được bỏ trống email</div>
|
||||
<div *ngIf="email?.errors?.email">Email không hợp lệ, vui lòng nhập lại</div>
|
||||
</div>
|
||||
<div class="form-button d-flex justify-content-around">
|
||||
<button class="btn btn-primary" type="submit" (click)="sendPasswordResetMail()">Tiếp
|
||||
tục</button>
|
||||
<button type="button" class="btn btn-danger btn-back" [routerLink]="['/auth', 'login']">Quay
|
||||
lại</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</ng-template>
|
||||
</li>
|
||||
</ul>
|
||||
<div [ngbNavOutlet]="nav" class="mt-2"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-template #sendMailCompleted>
|
||||
<div class="modal-body text-center">
|
||||
<p>Đã gửi đường dẫn thay đổi mật khẩu đến email của bạn</p>
|
||||
<p>Vui lòng kiểm tra hòm thư</p>
|
||||
<button type="button" class="btn btn-primary" (click)="gmail()">Gmail</button>
|
||||
<button type="button" class="btn btn-secondary" (click)="closeLayer1()">Đóng</button>
|
||||
</div>
|
||||
</ng-template>
|
||||
@@ -0,0 +1,38 @@
|
||||
.backgound-food {
|
||||
background-image: url("../../../../assets/images/background-login.jpg");
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
z-index: -99;
|
||||
|
||||
@media (max-width:768px) {
|
||||
.disable-pink {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.email-img-box {
|
||||
|
||||
.email-img {
|
||||
max-width: 351px;
|
||||
padding-bottom: 20px;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.fa-envelope-o {
|
||||
font-size: 38px;
|
||||
margin-right: 12px;
|
||||
color: #8b8b8b;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-back {
|
||||
border-radius: 25px;
|
||||
margin-top: 20px;
|
||||
font-weight: 400;
|
||||
padding: 11px 45px;
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
import { Component, OnInit, TemplateRef, ViewChild } from "@angular/core";
|
||||
import { FormControl, FormGroup, UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms";
|
||||
import { FirebaseService } from "../../../shared/service/firebase.service";
|
||||
import { Router } from "@angular/router";
|
||||
import { Validation } from "src/app/constants/Validation";
|
||||
import { BsModalRef, BsModalService } from "ngx-bootstrap/modal";
|
||||
|
||||
@Component({
|
||||
selector: "app-send-email",
|
||||
templateUrl: "./send-email.component.html",
|
||||
styleUrls: ["./send-email.component.scss"],
|
||||
})
|
||||
|
||||
// @ViewChild('sendMailCompleted') sendMailCompleted: TemplateRef<any>;
|
||||
|
||||
|
||||
export class SendEmailComponent {
|
||||
public sendEmailForm: FormGroup;
|
||||
public active = 1;
|
||||
|
||||
@ViewChild('sendMailCompleted') sendMailCompleted: TemplateRef<any>
|
||||
|
||||
constructor(
|
||||
private formBuilder: UntypedFormBuilder,
|
||||
private firebaseService: FirebaseService,
|
||||
private modalService: BsModalService,
|
||||
private router: Router
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
layer1: BsModalRef;
|
||||
|
||||
owlcarousel = [
|
||||
{
|
||||
title: "Chào mừng đến với Foodify",
|
||||
desc: "Foodify - Một trong những ứng dụng đặt đồ ăn tốt nhất hiện nay, được phát triển bởi Pyramide team",
|
||||
},
|
||||
{
|
||||
title: "Foodify - xu hướng mới",
|
||||
desc: "Với mục đích tạo ra những sản phẩm tốt nhất cho người dùng, chúng mình đã quyết định sử dụng các công nghệ mới nhất vào Foodify",
|
||||
},
|
||||
{
|
||||
title: "Về Pyramide Team",
|
||||
desc: "Pyramide team là một nhóm sinh viên trường Đại học FPT, team nghiên cứu và phát triển sản phẩm theo công nghệ Angular và Spring Boot",
|
||||
},
|
||||
];
|
||||
owlcarouselOptions = {
|
||||
loop: true,
|
||||
items: 1,
|
||||
dots: true,
|
||||
};
|
||||
|
||||
ngOnInit() {
|
||||
this.sendEmailForm = this.formBuilder.group({
|
||||
email: new FormControl("", [Validators.required, Validators.email]),
|
||||
});
|
||||
}
|
||||
|
||||
sendPasswordResetMail() {
|
||||
if (this.sendEmailForm.invalid) {
|
||||
this.sendEmailForm.markAllAsTouched();
|
||||
return;
|
||||
}
|
||||
this.firebaseService.resetPassword(this.email.value);
|
||||
this.layer1 = this.modalService.show(this.sendMailCompleted, { class: "modal-sm" });
|
||||
}
|
||||
|
||||
gmail() {
|
||||
this.layer1.hide();
|
||||
window.location.assign("https://mail.google.com/");
|
||||
}
|
||||
|
||||
closeLayer1() {
|
||||
this.layer1.hide();
|
||||
}
|
||||
|
||||
get email() {
|
||||
return this.sendEmailForm.get("email");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,388 @@
|
||||
<!-- Container-fluid starts-->
|
||||
<div class="backgound-food" [ngClass]="{'change-height': active === 2}">
|
||||
<div class="d-flex justify-content-center align-items-center">
|
||||
<div class="form-shop-box">
|
||||
<div class="d-flex justify-content-center align-items-center ">
|
||||
<div class="card tab2-card form-shop-item">
|
||||
<div class="card-header">
|
||||
<h2 style="color: lightcoral" class="font-weight-bold">Đăng ký shop</h2>
|
||||
</div>
|
||||
<div class="card-body tab2-card">
|
||||
<ul ngbNav #nav="ngbNav" [(activeId)]="active" class="nav-tabs">
|
||||
<li [ngbNavItem]="1">
|
||||
<a ngbNavLink>Tài khoản</a>
|
||||
<ng-template ngbNavContent>
|
||||
<form [formGroup]="addUserForm" class="needs-validation user-add" novalidate>
|
||||
<h4>Chi tiết tài khoản</h4>
|
||||
<!-- avatar -->
|
||||
<div class="form-group row">
|
||||
<div class="col-xl-3 col-md-4">
|
||||
<label for="validationCustom0"><span>*</span> Ảnh đại diện</label>
|
||||
</div>
|
||||
<div class="col-xl-8 col-md-7">
|
||||
<div class="d-flex align-items-center">
|
||||
<button *ngIf="!userImageChoosen" type="submit" class="btn btn-success"
|
||||
(click)="chooseImg(chooseUserImage)">
|
||||
Chọn ảnh
|
||||
</button>
|
||||
<button *ngIf="userImageChoosen" type="submit" class="btn btn-secondary"
|
||||
(click)="chooseImg(chooseUserImage)">
|
||||
Thay đổi ảnh
|
||||
</button>
|
||||
<img class="rounded-circle border border-dark" [src]="avatar" *ngIf="avatar"
|
||||
style="width: 160px; height: 160px; margin-left: 20px" />
|
||||
</div>
|
||||
<!-- <div *ngIf="!userImageChoosen && (addUserForm.get('image')?.dirty || addUserForm.get('image')?.touched)" class="alert alert-danger mt-1">
|
||||
<div *ngIf="addUserForm.get('image').errors?.['required']">Vui lòng chọn ảnh đại diện.</div>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- full name -->
|
||||
<div class="form-group row">
|
||||
<div class="col-xl-3 col-md-4">
|
||||
<label for="validationCustom0"><span>*</span> Họ và tên</label>
|
||||
</div>
|
||||
<div class="col-xl-8 col-md-7">
|
||||
<input formControlName="fullName" class="form-control" type="text" placeholder="Họ và tên" />
|
||||
<div *ngIf="userFullName?.invalid && (userFullName?.dirty || userFullName?.touched)"
|
||||
class="alert alert-danger mt-1">
|
||||
<div *ngIf="userFullName?.errors?.['required']">Vui lòng không được bỏ trống
|
||||
tên.</div>
|
||||
<div *ngIf="userFullName?.errors?.['minlength']">Tên phải có ít nhất 2 kí tự
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- email -->
|
||||
<div class="form-group row">
|
||||
<div class="col-xl-3 col-md-4">
|
||||
<label for="validationCustom2"><span>*</span> Email</label>
|
||||
</div>
|
||||
<div class="col-xl-8 col-md-7">
|
||||
<input formControlName="email" class="form-control" type="email" placeholder="Email" />
|
||||
<div *ngIf="userEmail?.invalid && (userEmail?.dirty || userEmail?.touched)"
|
||||
class="alert alert-danger mt-1">
|
||||
<div *ngIf="userEmail?.errors?.['required']">Vui lòng không được bỏ trống
|
||||
email.</div>
|
||||
<div *ngIf="userEmail?.errors?.email">Email không hợp lệ, vui lòng nhập lại
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- date of birth -->
|
||||
<div class="form-group row">
|
||||
<div class="col-xl-3 col-md-4">
|
||||
<label for="validationCustom2"><span>*</span> Ngày Sinh</label>
|
||||
</div>
|
||||
<div class="col-xl-8 col-md-7">
|
||||
<input type="date" formControlName="dateOfBirth" class="form-control" placeholder="Ngày sinh" />
|
||||
<div *ngIf="userDateOfBirth?.invalid && (userDateOfBirth?.dirty || userDateOfBirth?.touched)"
|
||||
class="alert alert-danger mt-1">
|
||||
<div *ngIf="userDateOfBirth?.errors?.['required']">Vui lòng không được bỏ
|
||||
trống ngày sinh.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- phone number -->
|
||||
<div class="form-group row">
|
||||
<div class="col-xl-3 col-md-4">
|
||||
<label for="validationCustom2"><span>*</span> Số Điện Thoại</label>
|
||||
</div>
|
||||
<div class="col-xl-8 col-md-7">
|
||||
<input formControlName="phoneNumber" class="form-control" type="tel"
|
||||
placeholder="Số điện thoại" />
|
||||
<div *ngIf="userPhoneNumber?.invalid && (userPhoneNumber?.dirty || userPhoneNumber?.touched)"
|
||||
class="alert alert-danger mt-1">
|
||||
<div *ngIf="userPhoneNumber?.errors?.['required']">Vui lòng không được bỏ
|
||||
trống số điện thoại.</div>
|
||||
<div *ngIf="userPhoneNumber?.errors?.['pattern']">Số điện thoại phải có tối
|
||||
đa 10 số</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- identified code -->
|
||||
<div class="form-group row">
|
||||
<div class="col-xl-3 col-md-4">
|
||||
<label for="validationCustom2"><span>*</span> CMND/CCCD</label>
|
||||
</div>
|
||||
<div class="col-xl-8 col-md-7">
|
||||
<input formControlName="identifiedCode" class="form-control" type="number"
|
||||
placeholder="CMND/CCCD" />
|
||||
<div
|
||||
*ngIf="userIdentifiedCode?.invalid && (userIdentifiedCode?.dirty || userIdentifiedCode?.touched)"
|
||||
class="alert alert-danger mt-1">
|
||||
<div *ngIf="userIdentifiedCode?.errors?.['required']">Vui lòng không được bỏ
|
||||
trống CMND/CCCD.</div>
|
||||
<div *ngIf="userIdentifiedCode?.errors?.['pattern']">CMND phải có tối đa 9
|
||||
số hoặc CCCD phải có tối đa 12 số</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<!-- Address -->
|
||||
<div class="form-group row">
|
||||
<div class="col-xl-3 col-md-4">
|
||||
<label for="validationCustom2"><span>*</span>Địa chỉ</label>
|
||||
</div>
|
||||
<div class="col-xl-8 col-md-7">
|
||||
<input formControlName="address" class="form-control" type="text" placeholder="Địa chỉ" />
|
||||
<div *ngIf="userAddress?.invalid && (userAddress?.dirty || userAddress?.touched)"
|
||||
class="alert alert-danger mt-1">
|
||||
<div *ngIf="userAddress?.errors?.['required']">Vui lòng không được bỏ
|
||||
trống địa chỉ</div>
|
||||
<div *ngIf="userAddress?.errors?.['minlength']">Tên phải có ít nhất 8 kí tự</div>
|
||||
<!-- <div *ngIf="userAddress?.errors?.['pattern']">CMND phải có tối đa 9
|
||||
số hoặc CCCD phải có tối đa 12 số</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="needs-validation user-add">
|
||||
<!-- District -->
|
||||
<div class="form-group row">
|
||||
<div class="col-xl-3 col-md-4">
|
||||
<label for="validationCustom2"><span>*</span> Quận</label>
|
||||
</div>
|
||||
<div class="col-xl-8 col-md-7">
|
||||
<select [(ngModel)]="district" class="form-control" (change)="onDistrictSelected()">
|
||||
<option [selected]="true" [ngValue]="'none'">--- Chọn quận ---</option>
|
||||
<option *ngFor="let district of districts" [ngValue]="district.name">{{
|
||||
district.name }}
|
||||
</option>
|
||||
</select>
|
||||
<div *ngIf="!validDistrict" class="alert alert-danger mt-1">
|
||||
Vui lòng không được bỏ trống quận
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Wards -->
|
||||
<div *ngIf="isHaveDistrict" class="form-group row">
|
||||
<div class="col-xl-3 col-md-4">
|
||||
<label for="validationCustom2"><span>*</span> Phường</label>
|
||||
</div>
|
||||
<div class="col-xl-8 col-md-7">
|
||||
<select [(ngModel)]="ward" class="form-control">
|
||||
<option [ngValue]="'none'">--- Chọn phường ---</option>
|
||||
<option *ngFor="let ward of wards">{{ ward.name }}
|
||||
</option>
|
||||
</select>
|
||||
<div *ngIf="!validWard" class="alert alert-danger mt-1">
|
||||
Vui lòng không được bỏ trống phường
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form [formGroup]="passwordForm" class="needs-validation user-add" novalidate>
|
||||
<!-- Password -->
|
||||
<div class="form-group row">
|
||||
<div class="col-xl-3 col-md-4">
|
||||
<label for="validationCustom2"><span>*</span> Mật khẩu</label>
|
||||
</div>
|
||||
<div class="col-xl-8 col-md-7">
|
||||
<div class="form-control input-password-holder">
|
||||
<input formControlName="password" class="input-password"
|
||||
type="{{ showPassword ? 'text' : 'password' }}" placeholder="Mật khẩu" />
|
||||
<span class="icon-holder-eye" (click)="showPassword = !showPassword">
|
||||
<i class="{{ showPassword ? 'fa fa-eye-slash' : 'fa fa-eye' }}"></i>
|
||||
</span>
|
||||
</div>
|
||||
<div *ngIf="userPassword?.invalid && (userPassword?.dirty || userPassword?.touched)"
|
||||
class="alert alert-danger mt-1">
|
||||
<div *ngIf="userPassword?.errors?.['required']">Vui lòng không được bỏ trống mật khẩu</div>
|
||||
<div *ngIf="userPassword?.errors?.['pattern']">
|
||||
Mật khẩu phải chứa ít nhất 8 ký tự, trong đó gồm một ký tự số, một
|
||||
chữ hoa, một chữ thường và một ký
|
||||
tự đặc biệt.
|
||||
<br />
|
||||
Mật khẩu không được chứa khoảng trắng.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Confirm Password -->
|
||||
<div class="form-group row">
|
||||
<div class="col-xl-3 col-md-4">
|
||||
<label for="validationCustom2"><span>*</span>Nhập lại mật khẩu</label>
|
||||
</div>
|
||||
<div class="col-xl-8 col-md-7">
|
||||
<div class="form-control input-password-holder">
|
||||
<input formControlName="confirmPassword" class="input-password"
|
||||
type="{{ showPassword ? 'text' : 'password' }}" placeholder="Xác nhận mật khẩu" />
|
||||
<span class="icon-holder-eye" (click)="showPassword = !showPassword">
|
||||
<i class="{{ showPassword ? 'fa fa-eye-slash' : 'fa fa-eye' }}"></i>
|
||||
</span>
|
||||
</div>
|
||||
<!-- <input formControlName="confirmPassword" class="form-control" type="text" placeholder="Xác nhận mật khẩu"/> -->
|
||||
<div
|
||||
*ngIf="userConfirmPassword?.invalid && (userConfirmPassword?.dirty || userConfirmPassword?.touched)"
|
||||
class="alert alert-danger mt-1">
|
||||
<div *ngIf="userConfirmPassword?.errors?.['required']">Vui lòng không được bỏ trống mật khẩu
|
||||
</div>
|
||||
<div *ngIf="userConfirmPassword?.errors?.['pattern']">
|
||||
Mật khẩu phải chứa ít nhất 8 ký tự, trong đó gồm một ký tự số, một
|
||||
chữ hoa, một chữ thường và một ký
|
||||
tự đặc biệt.
|
||||
<br />
|
||||
Mật khẩu không được chứa khoảng trắng.
|
||||
</div>
|
||||
<div *ngIf="userConfirmPassword?.errors?.['confirmedValidator']">
|
||||
Mật khẩu xác nhận phải giống với mật khẩu đã nhập
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</ng-template>
|
||||
</li>
|
||||
<!-- --------- SHOP ----------- -->
|
||||
<li [ngbNavItem]="2">
|
||||
<a ngbNavLink>Shop đăng ký</a>
|
||||
<ng-template ngbNavContent>
|
||||
<div class="row product-adding">
|
||||
<div class="col-xl-5">
|
||||
<div class="add-product">
|
||||
<div class="row">
|
||||
<div class="col-xl-9 xl-50 col-sm-6 col-9">
|
||||
<img [src]="shopBanner" *ngIf="shopBanner" alt="" class="img-fluid image_zoom_1">
|
||||
</div>
|
||||
<!-- <div class="col-xl-3 xl-50 col-sm-6 col-3">
|
||||
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xl-7">
|
||||
<form [formGroup]="shopForm" class="needs-validation user-add" novalidate="">
|
||||
|
||||
<!-- Shop Banner -->
|
||||
<div class="form-group row">
|
||||
<div class="col-xl-3 col-md-4">
|
||||
<label for="validationCustom0"><span>*</span> Banner shop</label>
|
||||
</div>
|
||||
<div class="col-xl-8 col-md-7">
|
||||
<div class="d-flex align-items-center">
|
||||
<button *ngIf="!shopImageChoosen" type="submit" class="btn btn-success"
|
||||
(click)="chooseImg(chooseShopImage)">Chọn
|
||||
ảnh</button>
|
||||
<button *ngIf="shopImageChoosen" type="submit" class="btn btn-secondary"
|
||||
(click)="chooseImg(chooseShopImage)">Thay đổi ảnh</button>
|
||||
</div>
|
||||
<!-- <div *ngIf="!shopImageChoosen && (shopForm.get('banner')?.dirty || shopForm.get('banner')?.touched)" class="alert alert-danger mt-1">
|
||||
<div *ngIf="shopForm.get('banner').errors?.['required']">Vui lòng chọn ảnh banner của shop.</div>
|
||||
</div> -->
|
||||
<!-- <div *ngIf="imageUrl?.invalid && (imageUrl?.dirty || imageUrl?.touched)"
|
||||
class="alert alert-danger mt-1">
|
||||
<div *ngIf="imageUrl?.errors?.['required']">Vui lòng chọn ảnh đại diện.
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Shop Name -->
|
||||
<div class="form-group row">
|
||||
<div class="col-xl-3 col-md-4">
|
||||
<label for="validationCustom2"><span>*</span>Tên shop</label>
|
||||
</div>
|
||||
<div class="col-xl-8 col-md-7">
|
||||
<input formControlName="name" class="form-control" type="text" placeholder="Tên shop" />
|
||||
<div *ngIf="shopName?.invalid && (shopName?.dirty || shopName?.touched)"
|
||||
class="alert alert-danger mt-1">
|
||||
<div *ngIf="shopName?.errors?.['required']">Vui lòng không được bỏ trống tên shop</div>
|
||||
<div *ngIf="shopName?.errors?.['minlength']">Tên shop phải có ít nhất
|
||||
2 kí tự</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Shop Description -->
|
||||
<div class="form-group row">
|
||||
<div class="col-xl-3 col-md-4">
|
||||
<label for="validationCustom2"><span>*</span>Mô tả shop</label>
|
||||
</div>
|
||||
<div class="col-xl-8 col-md-7">
|
||||
<textarea formControlName="description" class="form-control" type="text"
|
||||
placeholder="Mô tả về shop"></textarea>
|
||||
<div
|
||||
*ngIf="shopDescription?.invalid && (shopDescription?.dirty || shopDescription?.touched)"
|
||||
class="alert alert-danger mt-1">
|
||||
<div *ngIf="shopDescription?.errors?.['required']">Vui lòng không được bỏ
|
||||
trống phần mô tả shop</div>
|
||||
<div *ngIf="shopDescription?.errors?.['minlength']">Mô tả phải có ít nhất 8 kí tự</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Is Student Shop -->
|
||||
<div class="form-group row">
|
||||
<div class="col-xl-3 col-md-4">
|
||||
<label for="validationCustom2"><span>*</span> Loại shop</label>
|
||||
</div>
|
||||
<div class="col-xl-8 col-md-7">
|
||||
<button *ngIf="isStudent" type="button" class="btn btn-secondary" (click)="swap()">Shop sinh
|
||||
viên
|
||||
</button>
|
||||
<button *ngIf="!isStudent" type="button" class="btn btn-primary" (click)="swap()">Shop
|
||||
thường
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</li>
|
||||
</ul>
|
||||
<div [ngbNavOutlet]="nav" class="mt-2"></div>
|
||||
<div class="pull-right">
|
||||
<button type="button" class="btn btn-danger mr-3" (click)="goBackToLogin()">Quay lại</button>
|
||||
<button type="submit" class="btn btn-primary" (click)="createUser(createSuccess)">Tạo tài khoản</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Container-fluid Ends-->
|
||||
|
||||
<ng-template #chooseUserImage>
|
||||
<div class="modal-body text-center">
|
||||
<p>Vui lòng chọn 1 ảnh</p>
|
||||
<input class="input-image" type="file" accept="image/*" (change)="onFileSelected($event)" />
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #chooseShopImage>
|
||||
<div class="modal-body text-center">
|
||||
<p>Vui lòng chọn 1 ảnh</p>
|
||||
<input class="input-image" type="file" accept="image/*" (change)="onShopFileSelected($event)" />
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #createSuccess>
|
||||
<div class="modal-body text-center">
|
||||
<p>Tạo tài khoản thành công. Vui lòng kiểm tra hòm thư để xác thực tài khoản</p>
|
||||
<button type="button" class="btn btn-primary" (click)="continue()">Tiếp tục
|
||||
</button>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #error_modal>
|
||||
<div class="modal-body text-center">
|
||||
<p>{{ errorItem }} đã tồn tại. Vui lòng chọn một {{ errorItem.toLowerCase() }} khác.</p>
|
||||
<button type="button" class="btn btn-primary" (click)="closeLayer2()">Tiếp tục</button>
|
||||
</div>
|
||||
</ng-template>
|
||||
@@ -0,0 +1,40 @@
|
||||
.backgound-food {
|
||||
background-image: url('../../../../assets/images/background-login.jpg');
|
||||
width: 100vw;
|
||||
height: 100%;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
z-index: -99;
|
||||
}
|
||||
|
||||
.change-height {
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
|
||||
.form-shop-box {
|
||||
width: 1300px;
|
||||
margin: 80px 0;
|
||||
|
||||
.form-shop-item {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.input-password-holder {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
.input-password {
|
||||
border: none;
|
||||
width: 100%;
|
||||
}
|
||||
.icon-holder-eye {
|
||||
color: #999a9b;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,474 @@
|
||||
import { Component, TemplateRef, ViewChild } from "@angular/core";
|
||||
import { AngularFireStorage } from "@angular/fire/compat/storage";
|
||||
import { FormBuilder, FormControl, FormGroup, Validators } from "@angular/forms";
|
||||
import { Router } from "@angular/router";
|
||||
import { BsModalRef, BsModalService } from "ngx-bootstrap/modal";
|
||||
import { EMPTY, finalize, switchMap } from "rxjs";
|
||||
import { Observable } from "rxjs-compat";
|
||||
import { Validation } from "src/app/constants/Validation";
|
||||
import { AuthService } from "src/app/shared/service/auth.service";
|
||||
import { DistrictService } from "src/app/shared/service/district.service";
|
||||
import { FirebaseService } from "src/app/shared/service/firebase.service";
|
||||
import { ShopService } from "src/app/shared/service/shop.service";
|
||||
import { UserService } from "src/app/shared/service/user.service";
|
||||
import { Address } from "src/app/shared/tables/address";
|
||||
import { District } from "src/app/shared/tables/district";
|
||||
import { Shop } from "src/app/shared/tables/shop";
|
||||
import { User } from "src/app/shared/tables/user";
|
||||
import { Ward } from "src/app/shared/tables/ward";
|
||||
import { environment } from "src/environments/environment";
|
||||
|
||||
@Component({
|
||||
selector: "app-signup",
|
||||
templateUrl: "./signup.component.html",
|
||||
styleUrls: ["./signup.component.scss"],
|
||||
})
|
||||
export class SignupComponent {
|
||||
// form
|
||||
public active = 1;
|
||||
addUserForm: FormGroup;
|
||||
passwordForm: FormGroup;
|
||||
shopForm: FormGroup;
|
||||
|
||||
// image
|
||||
avatar: string;
|
||||
shopBanner: string;
|
||||
defaultUserImg = environment.userDefaultImg;
|
||||
defaultShopImg = environment.shopDefaultImg;
|
||||
|
||||
// file
|
||||
downloadURL: Observable<string>;
|
||||
userImageFile: File;
|
||||
shopImageFile: File;
|
||||
imageLink;
|
||||
|
||||
// password
|
||||
showPassword = false;
|
||||
|
||||
// address
|
||||
isHaveDistrict: boolean;
|
||||
district: string = "none";
|
||||
ward: string = "none";
|
||||
validDistrict = true;
|
||||
validWard = true;
|
||||
|
||||
districts: District[];
|
||||
wards: Ward[];
|
||||
|
||||
userImageChoosen: boolean = false;
|
||||
shopImageChoosen: boolean = false;
|
||||
isStudent: boolean = true;
|
||||
|
||||
//Modal
|
||||
errorItem = '';
|
||||
layer1: BsModalRef;
|
||||
layer2: BsModalRef;
|
||||
@ViewChild('error_modal') errorModal: TemplateRef<any>;
|
||||
|
||||
constructor(
|
||||
private formBuilder: FormBuilder,
|
||||
private authService: AuthService,
|
||||
private userService: UserService,
|
||||
private districtService: DistrictService,
|
||||
private storage: AngularFireStorage,
|
||||
private shopService: ShopService,
|
||||
private modalService: BsModalService,
|
||||
private router: Router,
|
||||
private firebaseService: FirebaseService
|
||||
) {
|
||||
this.createUserForm();
|
||||
this.createPasswordForm();
|
||||
this.createShopForm();
|
||||
}
|
||||
|
||||
createUserForm() {
|
||||
this.addUserForm = this.formBuilder.group({
|
||||
fullName: new FormControl("", [Validators.required, Validators.minLength(2)]),
|
||||
email: new FormControl("", [Validators.required, Validators.email]),
|
||||
dateOfBirth: new FormControl("", [Validators.required]),
|
||||
phoneNumber: new FormControl("", [Validators.required, Validators.pattern(Validation.Regex.Phone)]),
|
||||
identifiedCode: new FormControl("", [Validators.required, Validators.pattern(Validation.Regex.IdentifiedCode)]),
|
||||
address: new FormControl("", [Validators.required, Validators.minLength(8)]),
|
||||
});
|
||||
}
|
||||
|
||||
createPasswordForm() {
|
||||
this.passwordForm = this.formBuilder.group(
|
||||
{
|
||||
password: new FormControl("", [Validators.required, Validators.pattern(Validation.Regex.Password)]),
|
||||
confirmPassword: new FormControl("", [Validators.required, Validators.pattern(Validation.Regex.Password)]),
|
||||
},
|
||||
{
|
||||
validator: this.ConfirmedValidator("password", "confirmPassword"),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Validation for password and confirm password
|
||||
ConfirmedValidator(controlName: string, matchingControlName: string) {
|
||||
return (formGroup: FormGroup) => {
|
||||
const control = formGroup.controls[controlName];
|
||||
const matchingControl = formGroup.controls[matchingControlName];
|
||||
if (matchingControl.errors && !matchingControl.errors.confirmedValidator) {
|
||||
return;
|
||||
}
|
||||
if (control.value !== matchingControl.value) {
|
||||
matchingControl.setErrors({ confirmedValidator: true });
|
||||
} else {
|
||||
matchingControl.setErrors(null);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
createShopForm() {
|
||||
this.shopForm = this.formBuilder.group({
|
||||
name: new FormControl("", [Validators.required, Validators.minLength(2)]),
|
||||
description: new FormControl("", [Validators.required, Validators.minLength(8)]),
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.getAllDistrict();
|
||||
}
|
||||
|
||||
/**
|
||||
* create User from Form
|
||||
*/
|
||||
createUser(template: TemplateRef<any>): Promise<void> {
|
||||
const newUser = new User();
|
||||
const newAddress = new Address();
|
||||
const newShop = new Shop();
|
||||
|
||||
newUser.fullName = this.userFullName.value;
|
||||
newUser.email = this.userEmail.value;
|
||||
newUser.dateOfBirth = this.userDateOfBirth.value;
|
||||
newUser.phoneNumber = this.userPhoneNumber.value;
|
||||
newUser.identifiedCode = this.userIdentifiedCode.value;
|
||||
newUser.defaultAddress = 0;
|
||||
newUser.isLocked = false;
|
||||
newUser.roleName = 'ROLE_SHOP';
|
||||
|
||||
if (this.district === 'none' || this.ward === 'none') {
|
||||
this.validDistrict = this.district !== 'none';
|
||||
this.validWard = this.ward !== 'none';
|
||||
} else {
|
||||
// Tiếp tục với quá trình tạo tài khoản
|
||||
this.validDistrict = true;
|
||||
this.validWard = true;
|
||||
}
|
||||
|
||||
|
||||
if (this.addUserForm.invalid || this.passwordForm.invalid || this.shopForm.invalid || this.district == 'none') {
|
||||
this.addUserForm.markAllAsTouched();
|
||||
this.passwordForm.markAllAsTouched();
|
||||
this.shopForm.markAllAsTouched();
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
newShop.name = this.shopName.value
|
||||
newShop.description = this.shopDescription.value;
|
||||
newShop.isStudent = this.isStudent;
|
||||
newShop.isEnabled = true;
|
||||
newShop.lat = '1';
|
||||
newShop.lng = '1';
|
||||
|
||||
|
||||
newAddress.address = this.userAddress.value;
|
||||
newAddress.district = this.district;
|
||||
if (this.district != "Huyện Hoàng Sa") newAddress.ward = this.ward;
|
||||
|
||||
this.authService.checkEmailOrPhoneNumberExist(newUser).subscribe((error) => {
|
||||
if (error.title == 'emailExist') {
|
||||
this.errorItem = 'Email';
|
||||
this.layer2 = this.modalService.show(this.errorModal, { class: 'modal-sm' });
|
||||
return Promise.reject();
|
||||
}
|
||||
else if (error.title == 'phoneNumExist') {
|
||||
this.errorItem = 'Số điện thoại';
|
||||
this.layer2 = this.modalService.show(this.errorModal, { class: 'modal-sm' });
|
||||
return Promise.reject();
|
||||
}
|
||||
else {
|
||||
if (this.userImageChoosen && this.shopImageChoosen) {
|
||||
this.uploadUserImage(this.userImageFile).then((url) => {
|
||||
newUser.imageUrl = url
|
||||
|
||||
this.authService.SignUpUser(newUser).pipe(
|
||||
switchMap((user) => {
|
||||
this.uploadShopImage(this.shopImageFile).then((url) => {
|
||||
newShop.userId = user.id
|
||||
newShop.imageUrl = url;
|
||||
this.authService.SignUpUserAddress(user.id, newAddress).subscribe({
|
||||
next: () => {
|
||||
this.firebaseService.signUp(newUser.email, this.userPassword.value);
|
||||
this.authService.SignUpShop(newShop).subscribe(() => {
|
||||
this.layer1 = this.modalService.show(template, { class: 'modal-sm' })
|
||||
})
|
||||
}
|
||||
});
|
||||
})
|
||||
return EMPTY; // Return an empty observable to prevent nested subscriptions
|
||||
})
|
||||
).subscribe({
|
||||
next: () => { },
|
||||
error: () => {
|
||||
this.errorItem = 'CCCD/CMND';
|
||||
this.layer2 = this.modalService.show(this.errorModal, { class: 'modal-sm' });
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
else if (this.userImageChoosen && !this.shopImageChoosen) {
|
||||
this.uploadUserImage(this.userImageFile).then((url) => {
|
||||
newUser.imageUrl = url
|
||||
|
||||
this.authService.SignUpUser(newUser).pipe(
|
||||
switchMap((user) => {
|
||||
newShop.userId = user.id
|
||||
newShop.imageUrl = this.defaultShopImg;
|
||||
this.authService.SignUpUserAddress(user.id, newAddress).subscribe({
|
||||
next: () => {
|
||||
this.firebaseService.signUp(newUser.email, this.userPassword.value);
|
||||
this.authService.SignUpShop(newShop).subscribe(() => {
|
||||
this.layer1 = this.modalService.show(template, { class: 'modal-sm' })
|
||||
})
|
||||
}
|
||||
});
|
||||
return EMPTY; // Return an empty observable to prevent nested subscriptions
|
||||
})
|
||||
).subscribe({
|
||||
next: () => { },
|
||||
error: () => {
|
||||
this.errorItem = 'CCCD/CMND';
|
||||
this.layer2 = this.modalService.show(this.errorModal, { class: 'modal-sm' });
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
else if (!this.userImageChoosen && this.shopImageChoosen) {
|
||||
newUser.imageUrl = this.defaultUserImg;
|
||||
|
||||
this.authService.SignUpUser(newUser).pipe(
|
||||
switchMap((user) => {
|
||||
this.uploadShopImage(this.shopImageFile).then((url) => {
|
||||
newShop.userId = user.id
|
||||
newShop.imageUrl = url;
|
||||
this.authService.SignUpUserAddress(user.id, newAddress).subscribe({
|
||||
next: () => {
|
||||
this.firebaseService.signUp(newUser.email, this.userPassword.value);
|
||||
this.authService.SignUpShop(newShop).subscribe(() => {
|
||||
this.layer1 = this.modalService.show(template, { class: 'modal-sm' })
|
||||
})
|
||||
}
|
||||
});
|
||||
})
|
||||
return EMPTY; // Return an empty observable to prevent nested subscriptions
|
||||
})
|
||||
).subscribe({
|
||||
next: () => { },
|
||||
error: () => {
|
||||
this.errorItem = 'CCCD/CMND';
|
||||
this.layer2 = this.modalService.show(this.errorModal, { class: 'modal-sm' });
|
||||
}
|
||||
})
|
||||
}
|
||||
else {
|
||||
newUser.imageUrl = this.defaultUserImg;
|
||||
|
||||
this.authService.SignUpUser(newUser).pipe(
|
||||
switchMap((user) => {
|
||||
newShop.userId = user.id
|
||||
newShop.imageUrl = this.defaultShopImg;
|
||||
this.authService.SignUpUserAddress(user.id, newAddress).subscribe({
|
||||
next: () => {
|
||||
this.firebaseService.signUp(newUser.email, this.userPassword.value);
|
||||
this.authService.SignUpShop(newShop).subscribe(() => {
|
||||
this.layer1 = this.modalService.show(template, { class: 'modal-sm' })
|
||||
})
|
||||
}
|
||||
});
|
||||
return EMPTY; // Return an empty observable to prevent nested subscriptions
|
||||
})
|
||||
).subscribe({
|
||||
next: () => { },
|
||||
error: () => {
|
||||
this.errorItem = 'CCCD/CMND';
|
||||
this.layer2 = this.modalService.show(this.errorModal, { class: 'modal-sm' });
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//Districts and Wards
|
||||
getAllDistrict() {
|
||||
this.districtService.getAllDistricts().subscribe((distrs) => {
|
||||
this.districts = distrs;
|
||||
});
|
||||
}
|
||||
|
||||
onDistrictSelected() {
|
||||
this.isHaveDistrict = false;
|
||||
this.districts.forEach((element: District) => {
|
||||
if (this.district == element.name && this.district != "Huyện Hoàng Sa") {
|
||||
this.isHaveDistrict = true;
|
||||
this.wards = element.wards;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
swap() {
|
||||
if (this.isStudent) {
|
||||
this.isStudent = false;
|
||||
} else {
|
||||
this.isStudent = true;
|
||||
}
|
||||
}
|
||||
|
||||
//Image Selected
|
||||
onFileSelected(event) {
|
||||
this.userImageChoosen = true;
|
||||
this.userImageFile = event.target.files[0];
|
||||
|
||||
const reader = new FileReader();
|
||||
if (event.target.files && event.target.files.length) {
|
||||
const [file] = event.target.files;
|
||||
reader.readAsDataURL(file);
|
||||
|
||||
reader.onload = () => {
|
||||
this.avatar = reader.result as string;
|
||||
localStorage.setItem("image", this.avatar);
|
||||
};
|
||||
}
|
||||
this.layer1.hide();
|
||||
}
|
||||
|
||||
//Shop Image Selected
|
||||
onShopFileSelected(event) {
|
||||
this.shopImageChoosen = true;
|
||||
this.shopImageFile = event.target.files[0];
|
||||
|
||||
const reader = new FileReader();
|
||||
if (event.target.files && event.target.files.length) {
|
||||
const [file] = event.target.files;
|
||||
reader.readAsDataURL(file);
|
||||
|
||||
reader.onload = () => {
|
||||
this.shopBanner = reader.result as string;
|
||||
localStorage.setItem("image", this.shopBanner);
|
||||
};
|
||||
}
|
||||
this.layer1.hide();
|
||||
}
|
||||
|
||||
uploadUserImage(fileUpload: File): Promise<string> {
|
||||
return new Promise<string>((resolve) => {
|
||||
let n = Date.now();
|
||||
const filePath = `UserImages/${n}`;
|
||||
|
||||
const fileRef = this.storage.ref(filePath);
|
||||
const task = this.storage.upload(`UserImages/${n}`, fileUpload);
|
||||
task
|
||||
.snapshotChanges()
|
||||
.pipe(
|
||||
finalize(() => {
|
||||
this.downloadURL = fileRef.getDownloadURL();
|
||||
this.downloadURL.subscribe((url) => {
|
||||
if (url) {
|
||||
resolve(url);
|
||||
}
|
||||
});
|
||||
})
|
||||
)
|
||||
.subscribe((url) => { });
|
||||
});
|
||||
}
|
||||
|
||||
uploadShopImage(fileUpload: File): Promise<string> {
|
||||
return new Promise<string>((resolve) => {
|
||||
let n = Date.now();
|
||||
const filePath = `Shops/${n}`;
|
||||
|
||||
const fileRef = this.storage.ref(filePath);
|
||||
const task = this.storage.upload(`Shops/${n}`, fileUpload);
|
||||
task
|
||||
.snapshotChanges()
|
||||
.pipe(
|
||||
finalize(() => {
|
||||
this.downloadURL = fileRef.getDownloadURL();
|
||||
this.downloadURL.subscribe((url) => {
|
||||
if (url) {
|
||||
resolve(url);
|
||||
}
|
||||
});
|
||||
})
|
||||
)
|
||||
.subscribe((url) => { });
|
||||
});
|
||||
}
|
||||
|
||||
chooseImg(template: TemplateRef<any>) {
|
||||
this.layer1 = this.modalService.show(template, { class: "modal-sm" });
|
||||
}
|
||||
|
||||
continue() {
|
||||
this.layer1.hide();
|
||||
this.router.navigate(["/vendors/list"]);
|
||||
}
|
||||
|
||||
closeLayer2() {
|
||||
this.layer2.hide();
|
||||
}
|
||||
|
||||
goBackToLogin() {
|
||||
this.router.navigate(['/auth/login']);
|
||||
}
|
||||
|
||||
//Getter
|
||||
get image() {
|
||||
return this.addUserForm.get("image");
|
||||
}
|
||||
get userFullName() {
|
||||
return this.addUserForm.get("fullName");
|
||||
}
|
||||
get userEmail() {
|
||||
return this.addUserForm.get("email");
|
||||
}
|
||||
get userDateOfBirth() {
|
||||
return this.addUserForm.get("dateOfBirth");
|
||||
}
|
||||
get userPhoneNumber() {
|
||||
return this.addUserForm.get("phoneNumber");
|
||||
}
|
||||
get userIdentifiedCode() {
|
||||
return this.addUserForm.get("identifiedCode");
|
||||
}
|
||||
get userAddress() {
|
||||
return this.addUserForm.get("address");
|
||||
}
|
||||
get userDistrict() {
|
||||
return this.addUserForm.get("district");
|
||||
}
|
||||
get userWard() {
|
||||
return this.addUserForm.get("ward");
|
||||
}
|
||||
|
||||
get userPassword() {
|
||||
return this.passwordForm.get("password");
|
||||
}
|
||||
get userConfirmPassword() {
|
||||
return this.passwordForm.get("confirmPassword");
|
||||
}
|
||||
|
||||
//Shop
|
||||
get banner() {
|
||||
return this.shopForm.get("banner");
|
||||
}
|
||||
get shopName() {
|
||||
return this.shopForm.get("name");
|
||||
}
|
||||
get shopDescription() {
|
||||
return this.shopForm.get("description");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
import { ListCouponComponent } from './list-coupon/list-coupon.component';
|
||||
import { CreateCouponComponent } from './create-coupon/create-coupon.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
children: [
|
||||
{
|
||||
path: 'list-coupons',
|
||||
component: ListCouponComponent,
|
||||
data: {
|
||||
title: "List Coupons",
|
||||
breadcrumb: "List Coupons"
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'create-coupons',
|
||||
component: CreateCouponComponent,
|
||||
data: {
|
||||
title: "Create Coupon",
|
||||
breadcrumb: "Create Coupons"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class CouponsRoutingModule { }
|
||||
@@ -0,0 +1,21 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { CouponsRoutingModule } from './coupons-routing.module';
|
||||
import { ListCouponComponent } from './list-coupon/list-coupon.component';
|
||||
import { CreateCouponComponent } from './create-coupon/create-coupon.component';
|
||||
import { SharedModule } from 'src/app/shared/shared.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [ListCouponComponent, CreateCouponComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
CouponsRoutingModule,
|
||||
NgbModule,
|
||||
ReactiveFormsModule,
|
||||
SharedModule,
|
||||
FormsModule
|
||||
]
|
||||
})
|
||||
export class CouponsModule { }
|
||||
@@ -0,0 +1,184 @@
|
||||
<!-- Container-fluid starts-->
|
||||
<div class="container-fluid">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Discount Coupon Details</h5>
|
||||
</div>
|
||||
<div class="card-body tab2-card">
|
||||
<ul ngbNav #nav="ngbNav" [(activeId)]="active" class="nav-tabs">
|
||||
<li [ngbNavItem]="1">
|
||||
<a ngbNavLink>General</a>
|
||||
<ng-template ngbNavContent>
|
||||
<form [formGroup]="generalForm" class="needs-validation" novalidate="">
|
||||
<h4>General</h4>
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group row">
|
||||
<div class="col-xl-3 col-md-4">
|
||||
<label for="validationCustom0"><span>*</span>
|
||||
Coupan Title</label>
|
||||
</div>
|
||||
<div class="col-md-7">
|
||||
<input class="form-control" formControlName="name"
|
||||
id="validationCustom0" type="text" required="">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-xl-3 col-md-4">
|
||||
<label for="validationCustom1"><span>*</span>
|
||||
Coupan Code</label>
|
||||
</div>
|
||||
<div class="col-md-7">
|
||||
<input class="form-control" formControlName="code"
|
||||
id="validationCustom1" type="text" required="">
|
||||
</div>
|
||||
<div class="valid-feedback">Please Provide a Valid Coupon Code.</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-xl-3 col-md-4">
|
||||
<label>Start Date</label>
|
||||
</div>
|
||||
<div class="col-md-7 ">
|
||||
<div class="input-group input-grp-p">
|
||||
<input class="datepicker-here form-control digits" ngbDatepicker
|
||||
formControlName="start_date" #f="ngbDatepicker">
|
||||
<div class="input-group-append">
|
||||
<button class="btn calendar" (click)="f.toggle()" type="button"><i
|
||||
class="fa fa-calendar"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-xl-3 col-md-4">
|
||||
<label>End Date</label>
|
||||
</div>
|
||||
<div class="col-md-7">
|
||||
<div class="input-group input-grp-p">
|
||||
<input class="datepicker-here form-control digits" ngbDatepicker
|
||||
formControlName="end_date" #c="ngbDatepicker">
|
||||
<div class="input-group-append">
|
||||
<button class="btn calendar" (click)="c.toggle()" type="button"><i
|
||||
class="fa fa-calendar"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-xl-3 col-md-4">
|
||||
<label>Free Shipping</label>
|
||||
</div>
|
||||
<div class="col-md-7">
|
||||
<div class="checkbox checkbox-primary">
|
||||
<input id="checkbox-primary-1" type="checkbox"
|
||||
formControlName="free_shipping" data-original-title="" title="">
|
||||
<label for="checkbox-primary-1">Allow Free Shipping</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-xl-3 col-md-4"><label>Quantity</label></div>
|
||||
<div class="col-md-7">
|
||||
<input class="form-control" formControlName="quantity" type="number"
|
||||
required="">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-xl-3 col-md-4"><label>Discount Type</label></div>
|
||||
<div class="col-md-7">
|
||||
<select class="custom-select form-select" required="">
|
||||
<option value="">--Select--</option>
|
||||
<option value="1">Percent</option>
|
||||
<option value="2">Fixed</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-xl-3 col-md-4">
|
||||
<label>Status</label>
|
||||
</div>
|
||||
<div class="col-md-7">
|
||||
<div class="checkbox checkbox-primary">
|
||||
<input id="checkbox-primary-2" formControlName="status" type="checkbox"
|
||||
data-original-title="" title="">
|
||||
<label for="checkbox-primary-2">Enable the Coupon</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</ng-template>
|
||||
</li>
|
||||
<li [ngbNavItem]="2">
|
||||
<a ngbNavLink>Restriction</a>
|
||||
<ng-template ngbNavContent>
|
||||
<form [formGroup]="restrictionForm" class="needs-validation" novalidate="">
|
||||
<h4>Restriction</h4>
|
||||
<div class="form-group row">
|
||||
<div class="col-xl-3 col-md-4"><label for="validationCustom3">Products</label></div>
|
||||
<div class="col-md-7"><input class="form-control" formControlName="products" id="validationCustom3"
|
||||
type="text" required="">
|
||||
</div>
|
||||
<div class="valid-feedback">Please Provide a Product Name.</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-xl-3 col-md-4"><label>Category</label></div>
|
||||
<div class="col-md-7">
|
||||
<select class="custom-select form-select" formControlName="category" required="">
|
||||
<option value="">--Select--</option>
|
||||
<option value="1">Electronics</option>
|
||||
<option value="2">Clothes</option>
|
||||
<option value="2">Shoes</option>
|
||||
<option value="2">Digital</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-xl-3 col-md-4"><label for="validationCustom4">Minimum Spend</label></div>
|
||||
<div class="col-md-7">
|
||||
<input class="form-control" formControlName="min" id="validationCustom4"
|
||||
type="number">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-xl-3 col-md-4">
|
||||
<label for="validationCustom5">Maximum Spend</label>
|
||||
</div>
|
||||
<div class="col-md-7">
|
||||
<input class="form-control" formControlName="max" id="validationCustom5"
|
||||
type="number">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</ng-template>
|
||||
</li>
|
||||
<li [ngbNavItem]="3">
|
||||
<a ngbNavLink>Usage</a>
|
||||
<ng-template ngbNavContent>
|
||||
<form [formGroup]="usageForm" class="needs-validation" novalidate="">
|
||||
<h4>Usage Limits</h4>
|
||||
<div class="form-group row">
|
||||
<div class="col-xl-3 col-md-4"><label for="validationCustom6">Per Limit</label></div>
|
||||
<div class="col-md-7"><input class="form-control" formControlName="limit" id="validationCustom6"
|
||||
type="number">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-xl-3 col-md-4"><label for="validationCustom7">Per Customer</label></div>
|
||||
<div class="col-md-7"><input class="form-control" formControlName="customer" id="validationCustom7"
|
||||
type="number">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</ng-template>
|
||||
</li>
|
||||
</ul>
|
||||
<div [ngbNavOutlet]="nav" class="mt-2"></div>
|
||||
<div class="pull-right">
|
||||
<button type="button" class="btn btn-primary">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Container-fluid Ends-->
|
||||
@@ -0,0 +1,61 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
|
||||
import { NgbDateStruct, NgbDate, NgbCalendar, NgbDatepickerConfig } from '@ng-bootstrap/ng-bootstrap';
|
||||
|
||||
@Component({
|
||||
selector: 'app-create-coupon',
|
||||
templateUrl: './create-coupon.component.html',
|
||||
styleUrls: ['./create-coupon.component.scss']
|
||||
})
|
||||
export class CreateCouponComponent implements OnInit {
|
||||
public generalForm: UntypedFormGroup;
|
||||
public restrictionForm: UntypedFormGroup;
|
||||
public usageForm: UntypedFormGroup;
|
||||
public model: NgbDateStruct;
|
||||
public date: { year: number, month: number };
|
||||
public modelFooter: NgbDateStruct;
|
||||
public active = 1;
|
||||
|
||||
constructor(private formBuilder: UntypedFormBuilder, private calendar: NgbCalendar) {
|
||||
this.createGeneralForm();
|
||||
this.createRestrictionForm();
|
||||
this.createUsageForm();
|
||||
}
|
||||
|
||||
selectToday() {
|
||||
this.model = this.calendar.getToday();
|
||||
}
|
||||
|
||||
createGeneralForm() {
|
||||
this.generalForm = this.formBuilder.group({
|
||||
name: [''],
|
||||
code: [''],
|
||||
start_date: [''],
|
||||
end_date: [''],
|
||||
free_shipping: [''],
|
||||
quantity: [''],
|
||||
discount_type: [''],
|
||||
status: [''],
|
||||
});
|
||||
}
|
||||
|
||||
createRestrictionForm() {
|
||||
this.restrictionForm = this.formBuilder.group({
|
||||
products: [''],
|
||||
category: [''],
|
||||
min: [''],
|
||||
max: ['']
|
||||
})
|
||||
}
|
||||
|
||||
createUsageForm() {
|
||||
this.usageForm = this.formBuilder.group({
|
||||
limit: [''],
|
||||
customer: ['']
|
||||
})
|
||||
}
|
||||
ngOnInit() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<!-- Container-fluid starts-->
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Products Category</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="custom-datatable">
|
||||
<button class="btn btn-primary me-1 mb-3" style="float: right;">Delete</button>
|
||||
<div class="clearfix"></div>
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" sortable="title" (sort)="onSort($event)">Title</th>
|
||||
<th scope="col" sortable="code" (sort)="onSort($event)">Code</th>
|
||||
<th scope="col" sortable="discount" (sort)="onSort($event)">Discoount</th>
|
||||
<th scope="col" sortable="status" (sort)="onSort($event)">Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let item of tableItem$ | async ">
|
||||
|
||||
<th scope="row">
|
||||
<input type="checkbox" name="title_select" onclick="onSelect(item.id)">
|
||||
{{ item.title }}
|
||||
</th>
|
||||
<td>
|
||||
{{item.code}}
|
||||
</td>
|
||||
<td>{{item.discount}}</td>
|
||||
<td><i class="fa fa-circle {{item.status}} f-12"></i></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="d-flex justify-content-center p-2">
|
||||
<ngb-pagination
|
||||
[collectionSize]="(total$ | async)!" [(page)]="service.page" [pageSize]="service.pageSize">
|
||||
</ngb-pagination>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Container-fluid Ends-->
|
||||
@@ -0,0 +1,51 @@
|
||||
import {DecimalPipe} from '@angular/common';
|
||||
import {Component, OnInit, QueryList, ViewChildren} from '@angular/core';
|
||||
import {Observable} from 'rxjs';
|
||||
import {NgbdSortableHeader, SortEvent} from 'src/app/shared/directives/NgbdSortableHeader';
|
||||
import {TableService} from 'src/app/shared/service/table.service';
|
||||
import {LISTCOUPLEDB, ListCouponsDB} from 'src/app/shared/tables/list-coupon';
|
||||
|
||||
@Component({
|
||||
selector: 'app-list-coupon',
|
||||
templateUrl: './list-coupon.component.html',
|
||||
styleUrls: ['./list-coupon.component.scss'],
|
||||
providers: [TableService, DecimalPipe]
|
||||
})
|
||||
export class ListCouponComponent implements OnInit {
|
||||
|
||||
public selected = [];
|
||||
|
||||
public tableItem$: Observable<ListCouponsDB[]>;
|
||||
public searchText;
|
||||
total$: Observable<number>;
|
||||
|
||||
constructor(public service: TableService) {
|
||||
this.tableItem$ = service.tableItem$;
|
||||
this.total$ = service.total$;
|
||||
this.service.setUserData(LISTCOUPLEDB);
|
||||
}
|
||||
|
||||
@ViewChildren(NgbdSortableHeader) headers: QueryList<NgbdSortableHeader>;
|
||||
|
||||
onSort({column, direction}: SortEvent) {
|
||||
// resetting other headers
|
||||
this.headers.forEach((header) => {
|
||||
if (header.sortable !== column) {
|
||||
header.direction = '';
|
||||
}
|
||||
});
|
||||
|
||||
this.service.sortColumn = column;
|
||||
this.service.sortDirection = direction;
|
||||
|
||||
}
|
||||
|
||||
onSelect({selected}) {
|
||||
this.selected.splice(0, this.selected.length);
|
||||
this.selected.push(...selected);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
import { DashboardComponent } from './dashboard.component';
|
||||
import { AuthGuard } from 'src/app/shared/guard/auth-guard.service';
|
||||
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
children: [
|
||||
{
|
||||
path: 'default',
|
||||
component: DashboardComponent,
|
||||
canActivate: [AuthGuard],
|
||||
data: {
|
||||
title: "Trang chủ",
|
||||
breadcrumb: "Trang chủ"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class DashboardRoutingModule { }
|
||||
@@ -0,0 +1,726 @@
|
||||
<!-- Container-fluid starts-->
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-xl-3 col-md-6 xl-50">
|
||||
<div class="card o-hidden widget-cards">
|
||||
<div class="bg-warning card-body">
|
||||
<div class="media static-top-widget row">
|
||||
<div class="icons-widgets col-4">
|
||||
<div class="align-self-center text-center">
|
||||
<app-feather-icons *ngIf="isShop" [icon]="'dollar-sign'"
|
||||
class="font-warning"></app-feather-icons>
|
||||
<app-feather-icons *ngIf="!isShop" [icon]="'user'"
|
||||
class="font-warning"></app-feather-icons>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="isShop" class="media-body col-8"><span class="m-0">Thu nhập 30 ngày qua</span>
|
||||
<h3 class="mb-0">
|
||||
<span class="counter" [CountTo]="totalRevenue" [from]="0" [duration]="2">{{ totalRevenue
|
||||
| currency : "VND"
|
||||
}}</span>
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div *ngIf="!isShop" class="media-body col-8"><span class="m-0">Người dùng đăng ký mới</span>
|
||||
<h3 class="mb-0">
|
||||
<span class="counter" [CountTo]="totalUser" [from]="0" [duration]="2">{{ totalUser
|
||||
}}</span><small>
|
||||
người dùng</small>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-md-6 xl-50">
|
||||
<div class="card o-hidden widget-cards">
|
||||
<div class="bg-secondary card-body">
|
||||
<div class="media static-top-widget row">
|
||||
<div class="icons-widgets col-4">
|
||||
<div class="align-self-center text-center">
|
||||
<app-feather-icons [icon]="'package'" class="font-secondary"></app-feather-icons>
|
||||
</div>
|
||||
</div>
|
||||
<div class="media-body col-8"><span class="m-0">Tổng sản phẩm đã bán</span>
|
||||
<h3 class="mb-0"><span class="counter" [CountTo]="totalProducts" [from]="0"
|
||||
[duration]="2">{{ totalProducts }}</span><small> sản phẩm</small></h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-md-6 xl-50">
|
||||
<div class="card o-hidden widget-cards">
|
||||
<div class="bg-primary card-body">
|
||||
<div class="media static-top-widget row">
|
||||
<div class="icons-widgets col-4">
|
||||
<div class="align-self-center text-center">
|
||||
<app-feather-icons [icon]="'message-square'" class="font-primary"></app-feather-icons>
|
||||
</div>
|
||||
</div>
|
||||
<div class="media-body col-8"><span class="m-0">Số lượt đánh giá sản phẩm</span>
|
||||
<h3 class="mb-0"><span class="counter" [CountTo]="totalReviewCount" [from]="0"
|
||||
[duration]="2">{{ totalReviewCount }}</span><small> lượt</small></h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-md-6 xl-50">
|
||||
<div class="card o-hidden widget-cards">
|
||||
<div class="bg-danger card-body">
|
||||
<div class="media static-top-widget row">
|
||||
<div class="icons-widgets col-4">
|
||||
<div class="align-self-center text-center">
|
||||
<app-feather-icons [icon]="'star'" class="font-danger"></app-feather-icons>
|
||||
</div>
|
||||
</div>
|
||||
<div class="media-body col-8"><span class="m-0">Đánh giá trung bình</span>
|
||||
<h3 class="mb-0"><span class="counter" [CountTo]="totalAverageRating" [from]="0"
|
||||
[duration]="2">{{ totalAverageRating }}</span><small> /5</small></h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="col-xl-6 xl-100">-->
|
||||
<!-- <div class="card height-equal">-->
|
||||
<!-- <div class="card-header">-->
|
||||
<!-- <h5>Market Value</h5>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="card-body">-->
|
||||
<!-- <div class="market-chart">-->
|
||||
<!-- <x-chartist class="board-chart ct-golden-section" [data]="chart3.data" [type]="chart3.type"-->
|
||||
<!-- [options]="chart3.options" [events]="chart3.events">-->
|
||||
<!-- </x-chartist>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<div class="col-xl-12 xl-100">
|
||||
<div class="card height-equal">
|
||||
<div class="card-header">
|
||||
<h5 *ngIf="isShop">Đơn hàng của bạn</h5>
|
||||
<h5 *ngIf="!isShop">Các đơn hàng gần đây</h5>
|
||||
</div>
|
||||
<div class="card-body" *ngIf="orders.length">
|
||||
<div class=" user-status table-responsive latest-order-table">
|
||||
<table class="table table-bordernone">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Mã đơn hàng</th>
|
||||
<th scope="col">Tổng giá trị đơn hàng</th>
|
||||
<th scope="col">Phương thức thanh toán</th>
|
||||
<th scope="col">Trạng thái đơn hàng</th>
|
||||
<th scope="col">Địa chỉ</th>
|
||||
<th scope="col">Shipper</th>
|
||||
<th scope="col"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let order of orders; let i = index">
|
||||
<td>{{ order?.orderTrackingNumber }}</td>
|
||||
<td>{{ order?.total | currency : "VND" }}</td>
|
||||
<td><span [ngClass]="{
|
||||
badge: true,
|
||||
'badge-info': order.paymentMethod === 'ZALO PAY',
|
||||
'badge-success': order.paymentMethod === 'CASH'
|
||||
}">
|
||||
{{ order.paymentMethod === "CASH"
|
||||
? "Tiền mặt"
|
||||
: order.paymentMethod === "ZALO PAY"
|
||||
? "Zalo pay"
|
||||
: ""
|
||||
}}
|
||||
</span></td>
|
||||
<td><span [ngClass]="{
|
||||
badge: true,
|
||||
'badge-dark': order.status === 'AWAITING',
|
||||
'badge-warning': order.status === 'CONFIRMED',
|
||||
'badge-info': order.status === 'SHIPPING',
|
||||
'badge-success': order.status === 'COMPLETED',
|
||||
'badge-primary': order.status === 'CANCELED' || order.status === 'REJECT_DELIVERY'
|
||||
}">
|
||||
{{
|
||||
order.status === "AWAITING"
|
||||
? "Chờ xác nhận"
|
||||
: order.status === "CONFIRMED"
|
||||
? "Đã xác nhận"
|
||||
: order.status === "SHIPPING"
|
||||
? "Đang giao hàng"
|
||||
: order.status === "COMPLETED"
|
||||
? "Giao thành công"
|
||||
: order.status === "CANCELED"
|
||||
? "Đã huỷ đơn"
|
||||
: order.status === "REJECT_DELIVERY"
|
||||
? "Không nhận hàng"
|
||||
: ""
|
||||
}}
|
||||
</span></td>
|
||||
<td>{{ order?.address }}</td>
|
||||
<td *ngIf="order?.shipper?.user?.fullName != null">{{ order?.shipper?.user?.fullName
|
||||
}}</td>
|
||||
<td *ngIf="order?.shipper?.user?.fullName == null"><strong>Đang chờ...</strong></td>
|
||||
<td>
|
||||
<a [routerLink]="['/sales', 'detail-order', 'user', order.user.id, 'order', order.id]"
|
||||
style="cursor: pointer;">
|
||||
<i style="color: lightseagreen;" class="fa fa-eye f-12"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- <tr>
|
||||
<td>2</td>
|
||||
<td class="digits">$90.00</td>
|
||||
<td class="font-secondary">Ewallets</td>
|
||||
<td class="digits">Delivered</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>3</td>
|
||||
<td class="digits">$240.00</td>
|
||||
<td class="font-warning">Cash</td>
|
||||
<td class="digits">Delivered</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>4</td>
|
||||
<td class="digits">$120.00</td>
|
||||
<td class="font-primary">Direct Deposit</td>
|
||||
<td class="digits">$6523</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>5</td>
|
||||
<td class="digits">$50.00</td>
|
||||
<td class="font-primary">Bank Transfers</td>
|
||||
<td class="digits">Delivered</td>
|
||||
</tr> -->
|
||||
</tbody>
|
||||
</table>
|
||||
<a [routerLink]="['/sales', 'orders']" class="btn btn-primary">Xem tất cả đơn hàng</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class=" user-status table-responsive latest-order-table" *ngIf="!orders.length">
|
||||
<div class="d-flex justify-content-center p-2">
|
||||
<img src="../../../assets/images/error/no-order.png" alt="" srcset="">
|
||||
</div>
|
||||
<div class="d-flex justify-content-center p-2">
|
||||
<h4>Bạn chưa có đơn hàng nào</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <div class="col-xl-3 col-md-6 xl-50">
|
||||
<div class="card order-graph sales-carousel">
|
||||
<div class="card-header">
|
||||
<h6>Total Sales</h6>
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<div class="small-chartjs">
|
||||
<canvas baseChart id="small-graph-1" height="600" width="400"
|
||||
[datasets]="smallLineChartData" [labels]="smallLineChartLabels"
|
||||
[options]="smallLineChartOptions" [legend]="smallLineChartLegend"
|
||||
[type]="smallLineChartType" (chartHover)="chartHovered($event)"
|
||||
(chartClick)="chartClicked($event)"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="value-graph">
|
||||
<h3>42% <span><i class="fa fa-angle-up font-primary"></i></span></h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-start">
|
||||
<div class="media-body">
|
||||
<span>Sales Last Month</span>
|
||||
<h2 class="mb-0">9054</h2>
|
||||
<p>0.25% <span><i class="fa fa-angle-up"></i></span></p>
|
||||
<h5 class="f-w-600">Gross sales of August</h5>
|
||||
<p>Lorem Ipsum is simply dummy text of the printing and typesetting</p>
|
||||
</div>
|
||||
<div class="bg-primary b-r-8">
|
||||
<div class="small-box">
|
||||
<i data-feather="briefcase"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-md-6 xl-50">
|
||||
<div class="card order-graph sales-carousel">
|
||||
<div class="card-header">
|
||||
<h6>Total purchase</h6>
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<div class="small-chartjs">
|
||||
<canvas baseChart id="small-graph-2" height="60vw" width="140vw"
|
||||
[datasets]="smallLine2ChartData" [labels]="smallLine2ChartLabels"
|
||||
[options]="smallLine2ChartOptions" [legend]="smallLine2ChartLegend"
|
||||
[type]="smallLine2ChartType" (chartHover)="chartHovered($event)"
|
||||
(chartClick)="chartClicked($event)"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="value-graph">
|
||||
<h3>20% <span><i class="fa fa-angle-up font-secondary"></i></span></h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-start">
|
||||
<div class="media-body">
|
||||
<span>Monthly purchase</span>
|
||||
<h2 class="mb-0">2154</h2>
|
||||
<p>0.13% <span><i class="fa fa-angle-up"></i></span></p>
|
||||
<h5 class="f-w-600">Avg Gross purchase</h5>
|
||||
<p>Lorem Ipsum is simply dummy text of the printing and typesetting</p>
|
||||
</div>
|
||||
<div class="bg-secondary b-r-8">
|
||||
<div class="small-box">
|
||||
<i data-feather="credit-card"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-md-6 xl-50">
|
||||
<div class="card order-graph sales-carousel">
|
||||
<div class="card-header">
|
||||
<h6>Total cash transaction</h6>
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<div class="small-chartjs">
|
||||
<canvas baseChart id="small-graph-3" height="60vw" width="140vw"
|
||||
[datasets]="smallLine3ChartData" [labels]="smallLine3ChartLabels"
|
||||
[options]="smallLine3ChartOptions" [legend]="smallLine3ChartLegend"
|
||||
[type]="smallLine3ChartType" (chartHover)="chartHovered($event)"
|
||||
(chartClick)="chartClicked($event)"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="value-graph">
|
||||
<h3>28% <span><i class="fa fa-angle-up font-warning"></i></span></h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-start">
|
||||
<div class="media-body">
|
||||
<span>Cash on hand</span>
|
||||
<h2 class="mb-0">4672</h2>
|
||||
<p>0.8% <span><i class="fa fa-angle-up"></i></span></p>
|
||||
<h5 class="f-w-600">Details about cash</h5>
|
||||
<p>Lorem Ipsum is simply dummy text of the printing and typesetting</p>
|
||||
</div>
|
||||
<div class="bg-warning b-r-8">
|
||||
<div class="small-box">
|
||||
<i data-feather="shopping-cart"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-md-6 xl-50">
|
||||
<div class="card order-graph sales-carousel">
|
||||
<div class="card-header">
|
||||
<h6>Daily Deposits</h6>
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<div class="small-chartjs">
|
||||
<canvas baseChart id="small-graph-4" height="60vw" width="140vw"
|
||||
[datasets]="smallLine4ChartData" [labels]="smallLine4ChartLabels"
|
||||
[options]="smallLine4ChartOptions" [legend]="smallLine4ChartLegend"
|
||||
[type]="smallLine4ChartType" (chartHover)="chartHovered($event)"
|
||||
(chartClick)="chartClicked($event)"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="value-graph">
|
||||
<h3>75% <span><i class="fa fa-angle-up font-danger"></i></span></h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-start">
|
||||
<div class="media-body">
|
||||
<span>Security Deposits</span>
|
||||
<h2 class="mb-0">0782</h2>
|
||||
<p>0.25% <span><i class="fa fa-angle-up"></i></span></p>
|
||||
<h5 class="f-w-600">Gross sales of June</h5>
|
||||
<p>Lorem Ipsum is simply dummy text of the printing and typesetting</p>
|
||||
</div>
|
||||
<div class="bg-danger b-r-8">
|
||||
<div class="small-box">
|
||||
<i data-feather="calendar"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
<!-- <div class="col-sm-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Buy / Sell</h5>
|
||||
</div>
|
||||
<div class="card-body sell-graph">
|
||||
<canvas baseChart id="myGraph" [datasets]="lineChartData" [labels]="lineChartLabels"
|
||||
[options]="lineChartOptions" [legend]="lineChartLegend" [type]="lineChartType"
|
||||
(chartHover)="chartHovered($event)" (chartClick)="chartClicked($event)"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
<!-- <div class="col-xl-12 xl-100">-->
|
||||
<!-- <div class="card height-equal">-->
|
||||
<!-- <div class="card-header">-->
|
||||
<!-- <h5>Products Cart</h5>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="card-body">-->
|
||||
<!-- <div class="user-status table-responsive products-table">-->
|
||||
<!-- <table class="table table-bordernone mb-0">-->
|
||||
<!-- <thead>-->
|
||||
<!-- <tr>-->
|
||||
<!-- <th scope="col">Details</th>-->
|
||||
<!-- <th scope="col">Quantity</th>-->
|
||||
<!-- <th scope="col">Status</th>-->
|
||||
<!-- <th scope="col">Price</th>-->
|
||||
<!-- </tr>-->
|
||||
<!-- </thead>-->
|
||||
<!-- <tbody>-->
|
||||
<!-- <tr>-->
|
||||
<!-- <td>Simply dummy text of the printing</td>-->
|
||||
<!-- <td class="digits">1</td>-->
|
||||
<!-- <td class="font-primary">Pending</td>-->
|
||||
<!-- <td class="digits">$6523</td>-->
|
||||
<!-- </tr>-->
|
||||
<!-- <tr>-->
|
||||
<!-- <td>Long established</td>-->
|
||||
<!-- <td class="digits">5</td>-->
|
||||
<!-- <td class="font-secondary">Cancle</td>-->
|
||||
<!-- <td class="digits">$6523</td>-->
|
||||
<!-- </tr>-->
|
||||
<!-- <tr>-->
|
||||
<!-- <td>sometimes by accident</td>-->
|
||||
<!-- <td class="digits">10</td>-->
|
||||
<!-- <td class="font-secondary">Cancle</td>-->
|
||||
<!-- <td class="digits">$6523</td>-->
|
||||
<!-- </tr>-->
|
||||
<!-- <tr>-->
|
||||
<!-- <td>Classical Latin literature</td>-->
|
||||
<!-- <td class="digits">9</td>-->
|
||||
<!-- <td class="font-primary">Return</td>-->
|
||||
<!-- <td class="digits">$6523</td>-->
|
||||
<!-- </tr>-->
|
||||
<!-- <tr>-->
|
||||
<!-- <td>keep the site on the Internet</td>-->
|
||||
<!-- <td class="digits">8</td>-->
|
||||
<!-- <td class="font-primary">Pending</td>-->
|
||||
<!-- <td class="digits">$6523</td>-->
|
||||
<!-- </tr>-->
|
||||
<!-- <tr>-->
|
||||
<!-- <td>Molestiae consequatur</td>-->
|
||||
<!-- <td class="digits">3</td>-->
|
||||
<!-- <td class="font-secondary">Cancle</td>-->
|
||||
<!-- <td class="digits">$6523</td>-->
|
||||
<!-- </tr>-->
|
||||
<!-- <tr>-->
|
||||
<!-- <td>Pain can procure</td>-->
|
||||
<!-- <td class="digits">8</td>-->
|
||||
<!-- <td class="font-primary">Return</td>-->
|
||||
<!-- <td class="digits">$6523</td>-->
|
||||
<!-- </tr>-->
|
||||
<!-- </tbody>-->
|
||||
<!-- </table>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="col-xl-6 xl-100">-->
|
||||
<!-- <div class="card height-equal">-->
|
||||
<!-- <div class="card-header">-->
|
||||
<!-- <h5>Empolyee Status</h5>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="card-body">-->
|
||||
<!-- <div class="user-status table-responsive products-table">-->
|
||||
<!-- <table class="table table-bordernone mb-0">-->
|
||||
<!-- <thead>-->
|
||||
<!-- <tr>-->
|
||||
<!-- <th scope="col">Name</th>-->
|
||||
<!-- <th scope="col">Designation</th>-->
|
||||
<!-- <th scope="col">Skill Level</th>-->
|
||||
<!-- <th scope="col">Experience</th>-->
|
||||
<!-- </tr>-->
|
||||
<!-- </thead>-->
|
||||
<!-- <tbody>-->
|
||||
<!-- <tr>-->
|
||||
<!-- <td class="bd-t-none u-s-tb">-->
|
||||
<!-- <div class="align-middle image-sm-size"><img-->
|
||||
<!-- class="img-radius align-top m-r-15 rounded-circle"-->
|
||||
<!-- src="assets/images/dashboard/user2.jpg" alt="" data-original-title=""-->
|
||||
<!-- title="">-->
|
||||
<!-- <div class="d-inline-block">-->
|
||||
<!-- <h6>John Deo <span class="text-muted digits">(14+ Online)</span></h6>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </td>-->
|
||||
<!-- <td>Designer</td>-->
|
||||
<!-- <td>-->
|
||||
<!-- <div class="progress-showcase">-->
|
||||
<!-- <div class="progress" style="height: 8px;">-->
|
||||
<!-- <div class="progress-bar bg-primary" role="progressbar"-->
|
||||
<!-- style="width: 30%" aria-valuenow="50" aria-valuemin="0"-->
|
||||
<!-- aria-valuemax="100"></div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </td>-->
|
||||
<!-- <td class="digits">2 Year</td>-->
|
||||
<!-- </tr>-->
|
||||
<!-- <tr>-->
|
||||
<!-- <td class="bd-t-none u-s-tb">-->
|
||||
<!-- <div class="align-middle image-sm-size"><img-->
|
||||
<!-- class="img-radius align-top m-r-15 rounded-circle"-->
|
||||
<!-- src="assets/images/dashboard/user1.jpg" alt="" data-original-title=""-->
|
||||
<!-- title="">-->
|
||||
<!-- <div class="d-inline-block">-->
|
||||
<!-- <h6>Holio Mako <span class="text-muted digits">(250+ Online)</span></h6>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </td>-->
|
||||
<!-- <td>Developer</td>-->
|
||||
<!-- <td>-->
|
||||
<!-- <div class="progress-showcase">-->
|
||||
<!-- <div class="progress" style="height: 8px;">-->
|
||||
<!-- <div class="progress-bar bg-secondary" role="progressbar"-->
|
||||
<!-- style="width: 70%" aria-valuenow="50" aria-valuemin="0"-->
|
||||
<!-- aria-valuemax="100"></div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </td>-->
|
||||
<!-- <td class="digits">3 Year</td>-->
|
||||
<!-- </tr>-->
|
||||
<!-- <tr>-->
|
||||
<!-- <td class="bd-t-none u-s-tb">-->
|
||||
<!-- <div class="align-middle image-sm-size"><img-->
|
||||
<!-- class="img-radius align-top m-r-15 rounded-circle"-->
|
||||
<!-- src="assets/images/dashboard/man.png" alt="" data-original-title=""-->
|
||||
<!-- title="">-->
|
||||
<!-- <div class="d-inline-block">-->
|
||||
<!-- <h6>Mohsib lara<span class="text-muted digits">(99+ Online)</span></h6>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </td>-->
|
||||
<!-- <td>Tester</td>-->
|
||||
<!-- <td>-->
|
||||
<!-- <div class="progress-showcase">-->
|
||||
<!-- <div class="progress" style="height: 8px;">-->
|
||||
<!-- <div class="progress-bar bg-primary" role="progressbar"-->
|
||||
<!-- style="width: 60%" aria-valuenow="50" aria-valuemin="0"-->
|
||||
<!-- aria-valuemax="100"></div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </td>-->
|
||||
<!-- <td class="digits">5 Month</td>-->
|
||||
<!-- </tr>-->
|
||||
<!-- <tr>-->
|
||||
<!-- <td class="bd-t-none u-s-tb">-->
|
||||
<!-- <div class="align-middle image-sm-size"><img-->
|
||||
<!-- class="img-radius align-top m-r-15 rounded-circle"-->
|
||||
<!-- src="assets/images/dashboard/user.png" alt="" data-original-title=""-->
|
||||
<!-- title="">-->
|
||||
<!-- <div class="d-inline-block">-->
|
||||
<!-- <h6>Hileri Soli <span class="text-muted digits">(150+ Online)</span>-->
|
||||
<!-- </h6>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </td>-->
|
||||
<!-- <td>Designer</td>-->
|
||||
<!-- <td>-->
|
||||
<!-- <div class="progress-showcase">-->
|
||||
<!-- <div class="progress" style="height: 8px;">-->
|
||||
<!-- <div class="progress-bar bg-secondary" role="progressbar"-->
|
||||
<!-- style="width: 30%" aria-valuenow="50" aria-valuemin="0"-->
|
||||
<!-- aria-valuemax="100"></div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </td>-->
|
||||
<!-- <td class="digits">3 Month</td>-->
|
||||
<!-- </tr>-->
|
||||
<!-- <tr>-->
|
||||
<!-- <td class="bd-t-none u-s-tb">-->
|
||||
<!-- <div class="align-middle image-sm-size"><img-->
|
||||
<!-- class="img-radius align-top m-r-15 rounded-circle"-->
|
||||
<!-- src="assets/images/dashboard/designer.jpg" alt=""-->
|
||||
<!-- data-original-title="" title="">-->
|
||||
<!-- <div class="d-inline-block">-->
|
||||
<!-- <h6>Pusiz bia <span class="text-muted digits">(14+ Online)</span></h6>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </td>-->
|
||||
<!-- <td>Designer</td>-->
|
||||
<!-- <td>-->
|
||||
<!-- <div class="progress-showcase">-->
|
||||
<!-- <div class="progress" style="height: 8px;">-->
|
||||
<!-- <div class="progress-bar bg-primary" role="progressbar"-->
|
||||
<!-- style="width: 90%" aria-valuenow="50" aria-valuemin="0"-->
|
||||
<!-- aria-valuemax="100"></div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </td>-->
|
||||
<!-- <td class="digits">5 Year</td>-->
|
||||
<!-- </tr>-->
|
||||
<!-- </tbody>-->
|
||||
<!-- </table>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<div class="col-sm-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Tổng quan đơn hàng</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-xl-6 col-sm-6 xl-50">
|
||||
<div class="order-graph overflow-hidden">
|
||||
<h6>Vị trí đặt đơn</h6>
|
||||
<div class="chart-block chart-vertical-center">
|
||||
<ngx-charts-pie-chart class="pie-colours-1" [view]="view"
|
||||
[scheme]="doughnutChartColorScheme" [results]="pieData" [explodeSlices]="false"
|
||||
[labels]="doughnutChartShowLabels" [arcWidth]=0.50 [doughnut]="true"
|
||||
[animations]="false" [tooltipDisabled]="doughnutChartTooltip"
|
||||
[gradient]="doughnutChartGradient">
|
||||
</ngx-charts-pie-chart>
|
||||
</div>
|
||||
<div class="order-graph-bottom">
|
||||
<div class="media" *ngIf="thanhKheValue > 0">
|
||||
<div class="order-color-primary"></div>
|
||||
<div class="media-body">
|
||||
<h6 class="mb-0">Quận Thanh Khê <span class="pull-right">{{ thanhKheValue
|
||||
}} đơn hàng</span></h6>
|
||||
</div>
|
||||
</div>
|
||||
<div class="media" *ngIf="sonTraValue > 0">
|
||||
<div class="order-color-secondary"></div>
|
||||
<div class="media-body">
|
||||
<h6 class="mb-0">Quận Sơn Trà <span class="pull-right">{{ sonTraValue
|
||||
}} đơn hàng</span></h6>
|
||||
</div>
|
||||
</div>
|
||||
<div class="media" *ngIf="camLeValue > 0">
|
||||
<div class="order-color-danger"></div>
|
||||
<div class="media-body">
|
||||
<h6 class="mb-0">Quận Cẩm Lệ<span class="pull-right">{{ camLeValue }} đơn
|
||||
hàng</span></h6>
|
||||
</div>
|
||||
</div>
|
||||
<div class="media" *ngIf="lienChieuValue > 0">
|
||||
<div class="order-color-warning"></div>
|
||||
<div class="media-body">
|
||||
<h6 class="mb-0">Quận Liên Chiểu<span class="pull-right">{{ lienChieuValue
|
||||
}} đơn hàng</span></h6>
|
||||
</div>
|
||||
</div>
|
||||
<div class="media" *ngIf="haiChauValue > 0">
|
||||
<div class="order-color-success" style="background-color: #32CD32;"></div>
|
||||
<div class="media-body">
|
||||
<h6 class="mb-0">Quận Hải Châu<span class="pull-right">{{ haiChauValue }}
|
||||
đơn hàng</span></h6>
|
||||
</div>
|
||||
</div>
|
||||
<div class="media" *ngIf="hoaVangValue > 0">
|
||||
<div class="order-color-success" style="background-color: mediumpurple;"></div>
|
||||
<div class="media-body">
|
||||
<h6 class="mb-0">Huyện Hoà Vang<span class="pull-right">{{ hoaVangValue }}
|
||||
đơn hàng</span></h6>
|
||||
</div>
|
||||
</div>
|
||||
<div class="media" *ngIf="nguHanhSonValue > 0">
|
||||
<div class="order-color-success" style="background-color: deepskyblue;"></div>
|
||||
<div class="media-body">
|
||||
<h6 class="mb-0">Quận Ngũ Hành Sơn<span class="pull-right">{{
|
||||
nguHanhSonValue }} đơn hàng</span></h6>
|
||||
</div>
|
||||
</div>
|
||||
<div class="media" *ngIf="hoangSaValue > 0">
|
||||
<div class="order-color-success" style="background-color: olive;"></div>
|
||||
<div class="media-body">
|
||||
<h6 class="mb-0">Huyện Hoàng Sa<span class="pull-right">{{ hoangSaValue }}
|
||||
đơn hàng</span></h6>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-6 col-sm-6 xl-50">
|
||||
<div class="order-graph sm-order-space overflow-hidden">
|
||||
<h6>Top sản phẩm bán chạy</h6>
|
||||
<div class="peity-chart-dashboard text-center chart-vertical-center">
|
||||
<ngx-charts-pie-chart *ngIf="!isShop || (isShop && isData)" class="pie-colours-1"
|
||||
[view]="view" [scheme]="doughnutChartColorScheme" [results]="doughnutData"
|
||||
[explodeSlices]="false" [labels]="doughnutChartShowLabels" [arcWidth]=0.99
|
||||
[doughnut]="true" [animations]="false" [tooltipDisabled]="doughnutChartTooltip"
|
||||
[gradient]="doughnutChartGradient">
|
||||
</ngx-charts-pie-chart>
|
||||
</div>
|
||||
<div class="order-graph-bottom sales-location">
|
||||
<div class="media" *ngIf="products.length > 0">
|
||||
<div class="order-shape-primary"></div>
|
||||
<div class="media-body">
|
||||
<h6 class="mb-0 me-0">{{ products[0]?.name }} <span class="pull-right">{{
|
||||
products[0]?.sold }} lượt</span></h6>
|
||||
</div>
|
||||
</div>
|
||||
<div class="media" *ngIf="products.length > 1">
|
||||
<div class="order-shape-secondary"></div>
|
||||
<div class="media-body">
|
||||
<h6 class="mb-0 me-0">{{ products[1]?.name }} <span class="pull-right">{{
|
||||
products[1]?.sold }} lượt</span></h6>
|
||||
</div>
|
||||
</div>
|
||||
<div class="media" *ngIf="products.length > 2">
|
||||
<div class="order-shape-danger"></div>
|
||||
<div class="media-body">
|
||||
<h6 class="mb-0 me-0">{{ products[2]?.name }} <span class="pull-right">{{
|
||||
products[2]?.sold }} lượt</span></h6>
|
||||
</div>
|
||||
</div>
|
||||
<div class="media" *ngIf="products.length > 3">
|
||||
<div class="order-shape-warning"></div>
|
||||
<div class="media-body">
|
||||
<h6 class="mb-0 me-0">{{ products[3]?.name }} <span class="pull-right">{{
|
||||
products[3]?.sold }} lượt</span></h6>
|
||||
</div>
|
||||
</div>
|
||||
<div class="media" *ngIf="products.length > 4">
|
||||
<div class="order-shape-success"></div>
|
||||
<div class="media-body">
|
||||
<h6 class="mb-0 me-0">{{ products[4]?.name }} <span class="pull-right">{{
|
||||
products[4]?.sold }} lượt</span></h6>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="col-xl-6 xl-100">-->
|
||||
<!-- <div class="order-graph xl-space">-->
|
||||
<!-- <h6>Revenue for last month</h6>-->
|
||||
<!-- <div class="ct-4 flot-chart-container">-->
|
||||
<!-- <x-chartist [type]="chart5.type" [data]="ch art5.data" [options]="chart5.options">-->
|
||||
<!-- </x-chartist>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Container-fluid Ends-->
|
||||
@@ -0,0 +1,3 @@
|
||||
th, td {
|
||||
text-align: center;
|
||||
}
|
||||
@@ -0,0 +1,383 @@
|
||||
import { AfterViewInit, Component, OnInit } from '@angular/core';
|
||||
import * as chartData from '../../shared/data/chart';
|
||||
import { doughnutData, pieData } from '../../shared/data/chart';
|
||||
import { ShopService } from 'src/app/shared/service/shop.service';
|
||||
import { ProductService } from 'src/app/shared/service/product.service';
|
||||
import { Product } from 'src/app/shared/tables/product';
|
||||
import { Order } from 'src/app/shared/tables/order-list';
|
||||
import { OrderService } from 'src/app/shared/service/order.service';
|
||||
import { resolve } from 'path';
|
||||
import { forkJoin } from 'rxjs';
|
||||
import { UserService } from 'src/app/shared/service/user.service';
|
||||
import { FirebaseService } from 'src/app/shared/service/firebase.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-dashboard',
|
||||
templateUrl: './dashboard.component.html',
|
||||
styleUrls: ['./dashboard.component.scss']
|
||||
})
|
||||
export class DashboardComponent implements OnInit, AfterViewInit {
|
||||
//Log-in
|
||||
isShop: boolean = false;
|
||||
loggedId: number = Number(localStorage.getItem('user-id'))
|
||||
loggedRole = localStorage.getItem('user-role');
|
||||
shopId: number;
|
||||
|
||||
//Shop Properties
|
||||
totalRevenue: number = 0;
|
||||
totalProducts: number = 0;
|
||||
totalReviewCount: number = 0;
|
||||
totalAverageRating: number = 0;
|
||||
|
||||
//Orders
|
||||
orders: Order[] = [];
|
||||
|
||||
//Pagination Properties
|
||||
thePageNumber = 1;
|
||||
thePageSize = 5;
|
||||
sortBy = "orderTime";
|
||||
sortDir = "desc";
|
||||
theTotalElements = 0;
|
||||
|
||||
//District value
|
||||
thanhKheValue: number;
|
||||
sonTraValue: number;
|
||||
camLeValue: number;
|
||||
lienChieuValue: number;
|
||||
haiChauValue: number;
|
||||
hoaVangValue: number;
|
||||
nguHanhSonValue: number;
|
||||
hoangSaValue: number;
|
||||
|
||||
//Products
|
||||
products: Product[] = [];
|
||||
isData: boolean = false;
|
||||
|
||||
//Admin
|
||||
totalUser: number = 0;
|
||||
day: number = 30;
|
||||
|
||||
public doughnutData: Array<Object> = [];
|
||||
public pieData;
|
||||
|
||||
constructor(
|
||||
private userService: UserService,
|
||||
private shopService: ShopService,
|
||||
private productService: ProductService,
|
||||
private orderService: OrderService,
|
||||
private firebaseService: FirebaseService
|
||||
) {
|
||||
}
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
if (this.loggedRole != 'ROLE_ADMIN') {
|
||||
this.isShop = true;
|
||||
// this.shopId = Number(localStorage.getItem('shop-id'))
|
||||
|
||||
const shopIdPromise = new Promise<number>((resolve) => {
|
||||
const shopId = Number(localStorage.getItem('shop-id'));
|
||||
resolve(shopId);
|
||||
})
|
||||
|
||||
shopIdPromise.then((shopId) => {
|
||||
this.shopId = shopId;
|
||||
|
||||
this.productService.getProductsByShopIdNoPageable(this.shopId).subscribe((products) => {
|
||||
let i = 0;
|
||||
products.forEach(product => {
|
||||
this.totalReviewCount = this.totalReviewCount + product.reviewCount;
|
||||
this.totalProducts = this.totalProducts + product.sold;
|
||||
if (product.averageRating != 0) {
|
||||
this.totalAverageRating = this.totalAverageRating + product.averageRating;
|
||||
i++;
|
||||
}
|
||||
});
|
||||
if (i != 0) {
|
||||
this.totalAverageRating = this.totalAverageRating / i;
|
||||
}
|
||||
})
|
||||
|
||||
this.productService.getProductsByShopIdAndSort(this.shopId, 0, 5, 'sold', 'desc').subscribe((data) => {
|
||||
this.products = data.products;
|
||||
if (this.products.length > 4) {
|
||||
this.isData = true;
|
||||
}
|
||||
this.doughtnutData(data.products);
|
||||
})
|
||||
|
||||
this.orderService.getOrdersByShopId(this.shopId, this.thePageNumber - 1, this.thePageSize, this.sortBy, this.sortDir)
|
||||
.subscribe(this.processResult());
|
||||
this.shopService.getShopRevenue(this.shopId, 30).subscribe((res) => {
|
||||
this.totalRevenue = res;
|
||||
});
|
||||
this.valueOfShopDistrict();
|
||||
})
|
||||
}
|
||||
else {
|
||||
//ADMIN DO HERE
|
||||
|
||||
this.userService.countNewUser(this.day).subscribe((res) => {
|
||||
this.totalUser = res;
|
||||
})
|
||||
this.productService.getProductsNoPagination().subscribe((products) => {
|
||||
let i = 0;
|
||||
products.forEach(product => {
|
||||
this.totalReviewCount = this.totalReviewCount + product.reviewCount;
|
||||
this.totalProducts = this.totalProducts + product.sold;
|
||||
if (product.averageRating != 0) {
|
||||
this.totalAverageRating = this.totalAverageRating + product.averageRating;
|
||||
i++;
|
||||
}
|
||||
});
|
||||
this.totalAverageRating = this.totalAverageRating / i;
|
||||
})
|
||||
|
||||
this.productService.getProductsPaginationAndSort(0, 5, 'sold', 'desc').subscribe((data) => {
|
||||
this.products = data.products;
|
||||
this.doughtnutData(data.products)
|
||||
})
|
||||
|
||||
this.orderService
|
||||
.getOrdersPagination(this.thePageNumber - 1, this.thePageSize, this.sortBy, this.sortDir)
|
||||
.subscribe(this.processResult());
|
||||
|
||||
this.valueOfAdminDistrict();
|
||||
}
|
||||
}
|
||||
|
||||
processResult() {
|
||||
return (data: any) => {
|
||||
this.orders = data.orders;
|
||||
this.thePageNumber = data.page.pageNo + 1;
|
||||
this.thePageSize = data.page.pageSize;
|
||||
this.theTotalElements = data.page.totalElements;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// doughnut 2
|
||||
public view = chartData.view;
|
||||
public doughnutChartColorScheme = chartData.doughnutChartcolorScheme;
|
||||
public doughnutChartShowLabels = chartData.doughnutChartShowLabels;
|
||||
public doughnutChartGradient = chartData.doughnutChartGradient;
|
||||
public doughnutChartTooltip = chartData.doughnutChartTooltip;
|
||||
|
||||
public chart5 = chartData.chart5;
|
||||
|
||||
|
||||
// lineChart
|
||||
public lineChartData = chartData.lineChartData;
|
||||
public lineChartLabels = chartData.lineChartLabels;
|
||||
public lineChartOptions = chartData.lineChartOptions;
|
||||
public lineChartColors = chartData.lineChartColors;
|
||||
public lineChartLegend = chartData.lineChartLegend;
|
||||
public lineChartType = chartData.lineChartType;
|
||||
|
||||
// lineChart
|
||||
public smallLineChartData = chartData.smallLineChartData;
|
||||
public smallLineChartLabels = chartData.smallLineChartLabels;
|
||||
public smallLineChartOptions = chartData.smallLineChartOptions;
|
||||
public smallLineChartLegend = chartData.smallLineChartLegend;
|
||||
public smallLineChartType = chartData.smallLineChartType;
|
||||
|
||||
// lineChart
|
||||
public smallLine2ChartData = chartData.smallLine2ChartData;
|
||||
public smallLine2ChartLabels = chartData.smallLine2ChartLabels;
|
||||
public smallLine2ChartOptions = chartData.smallLine2ChartOptions;
|
||||
public smallLine2ChartLegend = chartData.smallLine2ChartLegend;
|
||||
public smallLine2ChartType = chartData.smallLine2ChartType;
|
||||
|
||||
// lineChart
|
||||
public smallLine3ChartData = chartData.smallLine3ChartData;
|
||||
public smallLine3ChartLabels = chartData.smallLine3ChartLabels;
|
||||
public smallLine3ChartOptions = chartData.smallLine3ChartOptions;
|
||||
public smallLine3ChartLegend = chartData.smallLine3ChartLegend;
|
||||
public smallLine3ChartType = chartData.smallLine3ChartType;
|
||||
|
||||
// lineChart
|
||||
public smallLine4ChartData = chartData.smallLine4ChartData;
|
||||
public smallLine4ChartLabels = chartData.smallLine4ChartLabels;
|
||||
public smallLine4ChartOptions = chartData.smallLine4ChartOptions;
|
||||
public smallLine4ChartColors = chartData.smallLine4ChartColors;
|
||||
public smallLine4ChartLegend = chartData.smallLine4ChartLegend;
|
||||
public smallLine4ChartType = chartData.smallLine4ChartType;
|
||||
|
||||
public chart3 = chartData.chart3;
|
||||
|
||||
|
||||
// events
|
||||
public chartClicked(e: any): void {
|
||||
}
|
||||
|
||||
public chartHovered(e: any): void {
|
||||
}
|
||||
|
||||
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
}
|
||||
|
||||
valueOfAdminDistrict() {
|
||||
const requests = [
|
||||
this.orderService.countOrderByDistrict('Thanh Khê'),
|
||||
this.orderService.countOrderByDistrict('Sơn Trà'),
|
||||
this.orderService.countOrderByDistrict('Cẩm Lệ'),
|
||||
this.orderService.countOrderByDistrict('Liên Chiểu'),
|
||||
this.orderService.countOrderByDistrict('Hải Châu'),
|
||||
this.orderService.countOrderByDistrict('Hoà Vang'),
|
||||
this.orderService.countOrderByDistrict('Ngũ Hành Sơn'),
|
||||
this.orderService.countOrderByDistrict('Hoàng Sa')
|
||||
];
|
||||
|
||||
forkJoin(requests).subscribe(
|
||||
(results: number[]) => {
|
||||
this.thanhKheValue = results[0];
|
||||
this.sonTraValue = results[1];
|
||||
this.camLeValue = results[2];
|
||||
this.lienChieuValue = results[3];
|
||||
this.haiChauValue = results[4];
|
||||
this.hoaVangValue = results[5];
|
||||
this.nguHanhSonValue = results[6];
|
||||
this.hoangSaValue = results[7];
|
||||
|
||||
this.pieData = [
|
||||
{
|
||||
value: this.thanhKheValue,
|
||||
name: "Quận Thanh Khê"
|
||||
|
||||
},
|
||||
{
|
||||
value: this.sonTraValue,
|
||||
name: "Quận Sơn Trà"
|
||||
},
|
||||
{
|
||||
value: this.camLeValue,
|
||||
name: "Quận Cẩm Lệ"
|
||||
},
|
||||
{
|
||||
value: this.lienChieuValue,
|
||||
name: "Quận Liên Chiểu"
|
||||
},
|
||||
{
|
||||
value: this.haiChauValue,
|
||||
name: "Quận Hải Châu"
|
||||
},
|
||||
{
|
||||
value: this.hoaVangValue,
|
||||
name: "Huyện Hoà Vang"
|
||||
},
|
||||
{
|
||||
value: this.nguHanhSonValue,
|
||||
name: "Quận Ngũ Hành Sơn"
|
||||
},
|
||||
{
|
||||
value: this.hoangSaValue,
|
||||
name: "Huyện Hoàng Sa"
|
||||
}
|
||||
]
|
||||
},
|
||||
(error) => {
|
||||
console.error('Error:', error);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
valueOfShopDistrict() {
|
||||
const requests = [
|
||||
this.orderService.countShopOrderByDistrict(this.shopId, 'Thanh Khê'),
|
||||
this.orderService.countShopOrderByDistrict(this.shopId, 'Sơn Trà'),
|
||||
this.orderService.countShopOrderByDistrict(this.shopId, 'Cẩm Lệ'),
|
||||
this.orderService.countShopOrderByDistrict(this.shopId, 'Liên Chiểu'),
|
||||
this.orderService.countShopOrderByDistrict(this.shopId, 'Hải Châu'),
|
||||
this.orderService.countShopOrderByDistrict(this.shopId, 'Hoà Vang'),
|
||||
this.orderService.countShopOrderByDistrict(this.shopId, 'Ngũ Hành Sơn'),
|
||||
this.orderService.countShopOrderByDistrict(this.shopId, 'Hoàng Sa')
|
||||
];
|
||||
|
||||
forkJoin(requests).subscribe(
|
||||
(results: number[]) => {
|
||||
this.thanhKheValue = results[0];
|
||||
this.sonTraValue = results[1];
|
||||
this.camLeValue = results[2];
|
||||
this.lienChieuValue = results[3];
|
||||
this.haiChauValue = results[4];
|
||||
this.hoaVangValue = results[5];
|
||||
this.nguHanhSonValue = results[6];
|
||||
this.hoangSaValue = results[7];
|
||||
|
||||
this.pieData = [
|
||||
{
|
||||
value: this.thanhKheValue,
|
||||
name: "Quận Thanh Khê"
|
||||
|
||||
},
|
||||
{
|
||||
value: this.sonTraValue,
|
||||
name: "Quận Sơn Trà"
|
||||
},
|
||||
{
|
||||
value: this.camLeValue,
|
||||
name: "Quận Cẩm Lệ"
|
||||
},
|
||||
{
|
||||
value: this.lienChieuValue,
|
||||
name: "Quận Liên Chiểu"
|
||||
},
|
||||
{
|
||||
value: this.haiChauValue,
|
||||
name: "Quận Hải Châu"
|
||||
},
|
||||
{
|
||||
value: this.hoaVangValue,
|
||||
name: "Huyện Hoà Vang"
|
||||
},
|
||||
{
|
||||
value: this.nguHanhSonValue,
|
||||
name: "Quận Ngũ Hành Sơn"
|
||||
},
|
||||
{
|
||||
value: this.hoangSaValue,
|
||||
name: "Huyện Hoàng Sa"
|
||||
}
|
||||
]
|
||||
},
|
||||
(error) => {
|
||||
console.error('Error:', error);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
doughtnutData(products: Product[]) {
|
||||
// products.forEach((product) => {
|
||||
// this.doughnutData.push({ value: product.sold, name: product.name });
|
||||
// })
|
||||
|
||||
this.doughnutData = [
|
||||
{
|
||||
value: products[0]?.sold,
|
||||
name: products[0]?.name
|
||||
|
||||
},
|
||||
{
|
||||
value: products[1]?.sold,
|
||||
name: products[1]?.name
|
||||
},
|
||||
{
|
||||
value: products[2]?.sold,
|
||||
name: products[2]?.name
|
||||
},
|
||||
{
|
||||
value: products[3]?.sold,
|
||||
name: products[3]?.name
|
||||
},
|
||||
{
|
||||
value: products[4]?.sold,
|
||||
name: products[4]?.name
|
||||
}
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { DashboardRoutingModule } from './dashboard-routing.module';
|
||||
import { DashboardComponent } from './dashboard.component';
|
||||
import { CountToModule } from 'angular-count-to';
|
||||
import { NgChartsModule } from 'ng2-charts';
|
||||
import { Ng2GoogleChartsModule } from 'ng2-google-charts';
|
||||
import { NgxChartsModule } from '@swimlane/ngx-charts';
|
||||
import { ChartistModule } from 'ng-chartist';
|
||||
import { SharedModule } from '../../shared/shared.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [DashboardComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
DashboardRoutingModule,
|
||||
CountToModule,
|
||||
SharedModule,
|
||||
NgChartsModule,
|
||||
Ng2GoogleChartsModule,
|
||||
NgxChartsModule,
|
||||
ChartistModule
|
||||
]
|
||||
})
|
||||
export class DashboardModule { }
|
||||
@@ -0,0 +1,21 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
import { InvoiceComponent } from './invoice.component';
|
||||
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: InvoiceComponent,
|
||||
data: {
|
||||
title: "Invoice",
|
||||
breadcrumb: "Invoice"
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class InvoiceRoutingModule { }
|
||||
@@ -0,0 +1,57 @@
|
||||
<!-- Container-fluid starts-->
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Invoice List</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="batchDelete" class="custom-datatable">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" sortable="no">No</th>
|
||||
<th scope="col" sortable="invoice">Invoice</th>
|
||||
<th scope="col" sortable="name" >Date</th>
|
||||
<th scope="col" sortable="name" >Shipping</th>
|
||||
<th scope="col" sortable="name" >Amount</th>
|
||||
<th scope="col" sortable="name" >Tax</th>
|
||||
<th scope="col" sortable="name" >Total</th>
|
||||
<th scope="col" sortable="name" >Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let item of tableItem$ | async ">
|
||||
<td scope="row">
|
||||
<span>{{item.no}}</span>
|
||||
</td>
|
||||
<td>
|
||||
{{item.invoice}}
|
||||
</td>
|
||||
<td>{{item.date}}</td>
|
||||
<td>{{item.shipping}}</td>
|
||||
<td>{{item.amount}}</td>
|
||||
<td>{{item.tax}}</td>
|
||||
<td>{{item.total}}</td>
|
||||
<td>
|
||||
<a href="javascript:void(0)"><i class='fa fa-edit f-12'></i></a>
|
||||
<a href="javascript:void(0)"><i class="fa fa-trash-o"></i></a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="d-flex justify-content-center p-2">
|
||||
<ngb-pagination
|
||||
[collectionSize]="(total$ | async)!" [(page)]="service.page" [pageSize]="service.pageSize">
|
||||
</ngb-pagination>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Container-fluid Ends-->
|
||||
@@ -0,0 +1,45 @@
|
||||
import { DecimalPipe } from '@angular/common';
|
||||
import { Component, OnInit, QueryList, ViewChildren } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { NgbdSortableHeader, SortEvent } from 'src/app/shared/directives/NgbdSortableHeader';
|
||||
import { TableService } from 'src/app/shared/service/table.service';
|
||||
import { InvoiceDB, INVOICEDB } from '../../shared/tables/invoice';
|
||||
|
||||
@Component({
|
||||
selector: 'app-invoice',
|
||||
templateUrl: './invoice.component.html',
|
||||
styleUrls: ['./invoice.component.scss'],
|
||||
providers: [TableService, DecimalPipe]
|
||||
})
|
||||
export class InvoiceComponent implements OnInit {
|
||||
|
||||
public tableItem$: Observable<InvoiceDB[]>;
|
||||
public searchText;
|
||||
total$: Observable<number>;
|
||||
|
||||
constructor(public service: TableService) {
|
||||
this.tableItem$ = service.tableItem$;
|
||||
this.total$ = service.total$;
|
||||
this.service.setUserData(INVOICEDB)
|
||||
}
|
||||
|
||||
@ViewChildren(NgbdSortableHeader) headers: QueryList<NgbdSortableHeader>;
|
||||
|
||||
onSort({ column, direction }: SortEvent) {
|
||||
// resetting other headers
|
||||
this.headers.forEach((header) => {
|
||||
if (header.sortable !== column) {
|
||||
header.direction = '';
|
||||
}
|
||||
});
|
||||
|
||||
this.service.sortColumn = column;
|
||||
this.service.sortDirection = direction;
|
||||
|
||||
}
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { InvoiceRoutingModule } from './invoice-routing.module';
|
||||
import { InvoiceComponent } from './invoice.component';
|
||||
import { SharedModule } from 'src/app/shared/shared.module';
|
||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
|
||||
@NgModule({
|
||||
declarations: [InvoiceComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
InvoiceRoutingModule,
|
||||
SharedModule,
|
||||
NgbModule
|
||||
]
|
||||
})
|
||||
export class InvoiceModule { }
|
||||
@@ -0,0 +1,39 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
import { RatesComponent } from './rates/rates.component';
|
||||
import { TranslationsComponent } from './translations/translations.component';
|
||||
import { TaxesComponent } from './taxes/taxes.component';
|
||||
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: 'translations',
|
||||
component: TranslationsComponent,
|
||||
data: {
|
||||
title: "Translations",
|
||||
breadcrumb: "Translations"
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'currency-rates',
|
||||
component: RatesComponent,
|
||||
data: {
|
||||
title: "Currency Rates",
|
||||
breadcrumb: "Currency Rates"
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'taxes',
|
||||
component: TaxesComponent,
|
||||
data: {
|
||||
title: 'Taxes',
|
||||
breadcrumb: 'Taxes'
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class LocalizationRoutingModule { }
|
||||
@@ -0,0 +1,21 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { LocalizationRoutingModule } from './localization-routing.module';
|
||||
import { TranslationsComponent } from './translations/translations.component';
|
||||
import { RatesComponent } from './rates/rates.component';
|
||||
import { TaxesComponent } from './taxes/taxes.component';
|
||||
import { SharedModule } from 'src/app/shared/shared.module';
|
||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [TranslationsComponent, RatesComponent, TaxesComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
LocalizationRoutingModule,
|
||||
SharedModule,
|
||||
NgbModule
|
||||
]
|
||||
})
|
||||
export class LocalizationModule { }
|
||||
@@ -0,0 +1,46 @@
|
||||
<!-- Container-fluid starts-->
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Currency Details</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="batchDelete" class="custom-datatable">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" sortable="title" (sort)="onSort($event)">Currency Title</th>
|
||||
<th scope="col" sortable="usd" (sort)="onSort($event)">USD</th>
|
||||
<th scope="col" sortable="code" (sort)="onSort($event)">Code</th>
|
||||
<th scope="col" sortable="rate" (sort)="onSort($event)">Exchange Rate</th>
|
||||
<th scope="col" >Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let item of tableItem$ | async ">
|
||||
<td scope="row">
|
||||
<span>{{item.title}}</span>
|
||||
</td>
|
||||
<td>
|
||||
{{item.usd}}
|
||||
</td>
|
||||
<td>{{item.code}}</td>
|
||||
<td>{{item.rate}}</td>
|
||||
<td>
|
||||
<a href="javascript:void(0)"><i class='fa fa-edit f-12'></i></a>
|
||||
<a href="javascript:void(0)"><i class="fa fa-trash-o"></i></a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Container-fluid Ends-->
|
||||
@@ -0,0 +1,46 @@
|
||||
import { DecimalPipe } from '@angular/common';
|
||||
import { Component, OnInit, QueryList, ViewChildren } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { NgbdSortableHeader, SortEvent } from 'src/app/shared/directives/NgbdSortableHeader';
|
||||
import { TableService } from 'src/app/shared/service/table.service';
|
||||
import { RateDB, RATEDB } from '../../../shared/tables/rate';
|
||||
|
||||
@Component({
|
||||
selector: 'app-rates',
|
||||
templateUrl: './rates.component.html',
|
||||
styleUrls: ['./rates.component.scss'],
|
||||
providers: [TableService, DecimalPipe]
|
||||
})
|
||||
export class RatesComponent implements OnInit {
|
||||
|
||||
public tableItem$: Observable<RateDB[]>;
|
||||
public searchText;
|
||||
total$: Observable<number>;
|
||||
|
||||
constructor(public service: TableService) {
|
||||
this.tableItem$ = service.tableItem$;
|
||||
this.total$ = service.total$;
|
||||
this.service.setUserData(RATEDB)
|
||||
}
|
||||
|
||||
@ViewChildren(NgbdSortableHeader) headers: QueryList<NgbdSortableHeader>;
|
||||
|
||||
onSort({ column, direction }: SortEvent) {
|
||||
// resetting other headers
|
||||
this.headers.forEach((header) => {
|
||||
if (header.sortable !== column) {
|
||||
header.direction = '';
|
||||
}
|
||||
});
|
||||
|
||||
this.service.sortColumn = column;
|
||||
this.service.sortDirection = direction;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<!-- Container-fluid starts-->
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Tax Details</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="batchDelete" class="custom-datatable">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" sortable="detail" (sort)="onSort($event)">Currency Title</th>
|
||||
<th scope="col" sortable="tax_schedule" (sort)="onSort($event)">USD</th>
|
||||
<th scope="col" sortable="rate" (sort)="onSort($event)" >Code</th>
|
||||
<th scope="col" sortable="total_amount" (sort)="onSort($event)">Exchange Rate</th>
|
||||
<th scope="col" (sort)="onSort($event)">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let item of tableItem$ | async ">
|
||||
<td scope="row">
|
||||
<span>{{item.detail}}</span>
|
||||
</td>
|
||||
<td>
|
||||
{{item.tax_schedule}}
|
||||
</td>
|
||||
<td>{{item.rate}}</td>
|
||||
<td>{{item.total_amount}}</td>
|
||||
<td>
|
||||
<a href="javascript:void(0)"><i class='fa fa-edit f-12'></i></a>
|
||||
<a href="javascript:void(0)"><i class="fa fa-trash-o"></i></a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Container-fluid Ends-->
|
||||
@@ -0,0 +1,43 @@
|
||||
import { DecimalPipe } from '@angular/common';
|
||||
import { Component, OnInit, QueryList, ViewChildren } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { NgbdSortableHeader, SortEvent } from 'src/app/shared/directives/NgbdSortableHeader';
|
||||
import { TableService } from 'src/app/shared/service/table.service';
|
||||
import { TaxesDB, TAXESDB } from '../../../shared/tables/taxes';
|
||||
|
||||
@Component({
|
||||
selector: 'app-taxes',
|
||||
templateUrl: './taxes.component.html',
|
||||
styleUrls: ['./taxes.component.scss'],
|
||||
providers: [TableService, DecimalPipe]
|
||||
})
|
||||
export class TaxesComponent implements OnInit {
|
||||
public tableItem$: Observable<TaxesDB[]>;
|
||||
public searchText;
|
||||
total$: Observable<number>;
|
||||
|
||||
constructor(public service: TableService) {
|
||||
this.tableItem$ = service.tableItem$;
|
||||
this.total$ = service.total$;
|
||||
this.service.setUserData(TAXESDB)
|
||||
}
|
||||
|
||||
@ViewChildren(NgbdSortableHeader) headers: QueryList<NgbdSortableHeader>;
|
||||
|
||||
onSort({ column, direction }: SortEvent) {
|
||||
// resetting other headers
|
||||
this.headers.forEach((header) => {
|
||||
if (header.sortable !== column) {
|
||||
header.direction = '';
|
||||
}
|
||||
});
|
||||
|
||||
this.service.sortColumn = column;
|
||||
this.service.sortDirection = direction;
|
||||
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<!-- Container-fluid starts-->
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Translations</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="batchDelete" class="custom-datatable">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" sortable="user_key" (sort)="onSort($event)">User Key</th>
|
||||
<th scope="col" sortable="russian" (sort)="onSort($event)">Russian</th>
|
||||
<th scope="col" sortable="arabic" (sort)="onSort($event)">Arbic</th>
|
||||
<th scope="col" sortable="english" (sort)="onSort($event)">English</th>
|
||||
<th scope="col" >Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let item of tableItem$ | async ">
|
||||
<td scope="row">
|
||||
<span>{{item.user_key}}</span>
|
||||
</td>
|
||||
<td>
|
||||
{{item.russian}}
|
||||
</td>
|
||||
<td>{{item.arabic}}</td>
|
||||
<td>{{item.english}}</td>
|
||||
<td>
|
||||
<a href="javascript:void(0)"><i class='fa fa-edit f-12'></i></a>
|
||||
<a href="javascript:void(0)"><i class="fa fa-trash-o"></i></a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="d-flex justify-content-center p-2">
|
||||
<ngb-pagination
|
||||
[collectionSize]="(total$ | async)!" [(page)]="service.page" [pageSize]="service.pageSize">
|
||||
</ngb-pagination>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Container-fluid Ends-->
|
||||
@@ -0,0 +1,45 @@
|
||||
import { DecimalPipe } from '@angular/common';
|
||||
import { Component, OnInit, QueryList, ViewChildren } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { NgbdSortableHeader, SortEvent } from 'src/app/shared/directives/NgbdSortableHeader';
|
||||
import { TableService } from 'src/app/shared/service/table.service';
|
||||
import { TRANSLATIONDB, TranslationsDB } from '../../../shared/tables/translations';
|
||||
|
||||
@Component({
|
||||
selector: 'app-translations',
|
||||
templateUrl: './translations.component.html',
|
||||
styleUrls: ['./translations.component.scss'],
|
||||
providers: [TableService, DecimalPipe]
|
||||
})
|
||||
export class TranslationsComponent implements OnInit {
|
||||
|
||||
public tableItem$: Observable<TranslationsDB[]>;
|
||||
public searchText;
|
||||
total$: Observable<number>;
|
||||
|
||||
constructor(public service: TableService) {
|
||||
this.tableItem$ = service.tableItem$;
|
||||
this.total$ = service.total$;
|
||||
this.service.setUserData(TRANSLATIONDB)
|
||||
}
|
||||
|
||||
@ViewChildren(NgbdSortableHeader) headers: QueryList<NgbdSortableHeader>;
|
||||
|
||||
onSort({ column, direction }: SortEvent) {
|
||||
// resetting other headers
|
||||
this.headers.forEach((header) => {
|
||||
if (header.sortable !== column) {
|
||||
header.direction = '';
|
||||
}
|
||||
});
|
||||
|
||||
this.service.sortColumn = column;
|
||||
this.service.sortDirection = direction;
|
||||
|
||||
}
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
import { MediaComponent } from './media/media.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: MediaComponent,
|
||||
data: {
|
||||
title: "Media",
|
||||
breadcrumb: "Media"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class MediaRoutingModule { }
|
||||
@@ -0,0 +1,21 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { MediaRoutingModule } from './media-routing.module';
|
||||
import { MediaComponent } from './media/media.component';
|
||||
import { NgxDropzoneModule } from 'ngx-dropzone';
|
||||
import { SharedModule } from 'src/app/shared/shared.module';
|
||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [MediaComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
MediaRoutingModule,
|
||||
NgxDropzoneModule,
|
||||
SharedModule,
|
||||
NgbModule
|
||||
]
|
||||
})
|
||||
export class MediaModule { }
|
||||
@@ -0,0 +1,67 @@
|
||||
<!-- Container-fluid starts-->
|
||||
<div class="container-fluid bulk-cate">
|
||||
<div class="card ">
|
||||
<div class="card-header">
|
||||
<h5>Dropzone Media</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="dropzone-custom">
|
||||
<ngx-dropzone class="dropzone-border" (change)="onSelect($event)">
|
||||
<ngx-dropzone-label>
|
||||
<div class="dz-message needsclick">
|
||||
<i class="fa fa-cloud-upload"></i>
|
||||
<h4 class="mb-0 f-w-600">Drop files here or click to upload.</h4>
|
||||
</div>
|
||||
</ngx-dropzone-label>
|
||||
<ngx-dropzone-preview *ngFor="let f of files" [removable]="true" (removed)="onRemove(f)">
|
||||
<ngx-dropzone-label>{{ f.name }} ({{ f.type }})</ngx-dropzone-label>
|
||||
</ngx-dropzone-preview>
|
||||
</ngx-dropzone>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Media File List</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="batchDelete" class="category-table custom-datatable media-datatable">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" sortable="action">Actions</th>
|
||||
<th scope="col" sortable="img" (sort)="onSort($event)">Image</th>
|
||||
<th scope="col" sortable="file_name" (sort)="onSort($event)">File Name</th>
|
||||
<th scope="col" sortable="url" (sort)="onSort($event)">URL</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let item of tableItem$ | async ">
|
||||
<td>
|
||||
<a href="javascript:void(0)"><i class='fa fa-edit f-12'></i></a>
|
||||
<a href="javascript:void(0)"><i class="fa fa-trash-o"></i></a>
|
||||
</td>
|
||||
<td scope="row">
|
||||
<img [src]="item.img" class="imgTable" style="width: 20px">
|
||||
</td>
|
||||
<td>
|
||||
{{item.file_name}}
|
||||
</td>
|
||||
<td>{{item.url}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
<div class="d-flex justify-content-center p-2 border-top-0">
|
||||
<ngb-pagination
|
||||
[collectionSize]="(total$ | async)!" [(page)]="service.page" [pageSize]="service.pageSize">
|
||||
</ngb-pagination>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Container-fluid Ends-->
|
||||
@@ -0,0 +1,55 @@
|
||||
import { DecimalPipe } from '@angular/common';
|
||||
import { Component, OnInit, QueryList, ViewChildren } from '@angular/core';
|
||||
import { DropzoneConfigInterface } from 'ngx-dropzone-wrapper';
|
||||
import { Observable } from 'rxjs';
|
||||
import { NgbdSortableHeader, SortEvent } from 'src/app/shared/directives/NgbdSortableHeader';
|
||||
import { TableService } from 'src/app/shared/service/table.service';
|
||||
import { MediaDB, MEDIADB } from 'src/app/shared/tables/media';
|
||||
|
||||
@Component({
|
||||
selector: 'app-media',
|
||||
templateUrl: './media.component.html',
|
||||
styleUrls: ['./media.component.scss'],
|
||||
providers: [TableService, DecimalPipe]
|
||||
})
|
||||
export class MediaComponent implements OnInit {
|
||||
|
||||
public tableItem$: Observable<MediaDB[]>;
|
||||
public searchText;
|
||||
total$: Observable<number>;
|
||||
|
||||
constructor(public service: TableService) {
|
||||
this.tableItem$ = service.tableItem$;
|
||||
this.total$ = service.total$;
|
||||
this.service.setUserData(MEDIADB)
|
||||
}
|
||||
|
||||
@ViewChildren(NgbdSortableHeader) headers: QueryList<NgbdSortableHeader>;
|
||||
|
||||
onSort({ column, direction }: SortEvent) {
|
||||
// resetting other headers
|
||||
this.headers.forEach((header) => {
|
||||
if (header.sortable !== column) {
|
||||
header.direction = '';
|
||||
}
|
||||
});
|
||||
|
||||
this.service.sortColumn = column;
|
||||
this.service.sortDirection = direction;
|
||||
|
||||
}
|
||||
|
||||
files: File[] = [];
|
||||
|
||||
onSelect(event) {
|
||||
this.files.push(...event.addedFiles);
|
||||
}
|
||||
|
||||
onRemove(event) {
|
||||
this.files.splice(this.files.indexOf(event), 1);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<!-- Container-fluid starts-->
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Add Menu</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form class="needs-validation">
|
||||
<div class="form-group row">
|
||||
<div class="col-xl-3 col-md-4"><label for="validationCustom0"><span>*</span> Menu Name</label></div>
|
||||
<div class="col-md-8"><input class="form-control" id="validationCustom0" type="text" required=""></div>
|
||||
</div>
|
||||
<div clalass="form-group row">
|
||||
<label class="col-xl-3 col-md-4">Status</label>
|
||||
<div class="col-xl-9 col-md-8">
|
||||
<div class="checkbox checkbox-primary">
|
||||
<input id="checkbox-primary-2" type="checkbox" data-original-title="" title="">
|
||||
<label for="checkbox-primary-2">Enable the Menu</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-primary">Save</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Container-fluid Ends-->
|
||||
@@ -0,0 +1,15 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-create-menu',
|
||||
templateUrl: './create-menu.component.html',
|
||||
styleUrls: ['./create-menu.component.scss']
|
||||
})
|
||||
export class CreateMenuComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<!-- Container-fluid starts-->
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Menu Lists</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="custom-datatable">
|
||||
<button class="btn btn-primary me-1 mb-3" style="float: right;" >Delete</button>
|
||||
<div class="clearfix"></div>
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th scope="col" sortable="name" (sort)="onSort($event)">Name</th>
|
||||
<th scope="col" sortable="status" (sort)="onSort($event)">Status</th>
|
||||
<th scope="col" sortable="created_on" (sort)="onSort($event)">Created On</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let item of tableItem$ | async ">
|
||||
<th> <input type="checkbox" name="title_select" onclick="onSelect(item.id)"></th>
|
||||
<td scope="row">
|
||||
{{item.name}}
|
||||
</td>
|
||||
<td>
|
||||
<i class="fa fa-circle {{item.status}} f-12"></i>
|
||||
</td>
|
||||
<td>{{item.created_on}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="d-flex justify-content-center p-2">
|
||||
<ngb-pagination
|
||||
[collectionSize]="(total$ | async)!" [(page)]="service.page" [pageSize]="service.pageSize">
|
||||
</ngb-pagination>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,51 @@
|
||||
import { DecimalPipe } from '@angular/common';
|
||||
import { Component, OnInit, QueryList, ViewChildren } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { NgbdSortableHeader, SortEvent } from 'src/app/shared/directives/NgbdSortableHeader';
|
||||
import { TableService } from 'src/app/shared/service/table.service';
|
||||
import { ListPagesDB } from 'src/app/shared/tables/list-pages';
|
||||
import { MENUDB, MenuDB } from 'src/app/shared/tables/menu';
|
||||
|
||||
@Component({
|
||||
selector: 'app-list-menu',
|
||||
templateUrl: './list-menu.component.html',
|
||||
styleUrls: ['./list-menu.component.scss'],
|
||||
providers: [TableService, DecimalPipe]
|
||||
})
|
||||
export class ListMenuComponent implements OnInit {
|
||||
|
||||
public selected = [];
|
||||
|
||||
public tableItem$: Observable<ListPagesDB[]>;
|
||||
public searchText;
|
||||
total$: Observable<number>;
|
||||
|
||||
constructor(public service: TableService) {
|
||||
this.tableItem$ = service.tableItem$;
|
||||
this.total$ = service.total$;
|
||||
this.service.setUserData(MENUDB)
|
||||
}
|
||||
|
||||
@ViewChildren(NgbdSortableHeader) headers: QueryList<NgbdSortableHeader>;
|
||||
|
||||
onSort({ column, direction }: SortEvent) {
|
||||
// resetting other headers
|
||||
this.headers.forEach((header) => {
|
||||
if (header.sortable !== column) {
|
||||
header.direction = '';
|
||||
}
|
||||
});
|
||||
|
||||
this.service.sortColumn = column;
|
||||
this.service.sortDirection = direction;
|
||||
|
||||
}
|
||||
|
||||
onSelect({ selected }) {
|
||||
this.selected.splice(0, this.selected.length);
|
||||
this.selected.push(...selected);
|
||||
}
|
||||
|
||||
ngOnInit() { }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
import { ListMenuComponent } from './list-menu/list-menu.component';
|
||||
import { CreateMenuComponent } from './create-menu/create-menu.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
children: [
|
||||
{
|
||||
path: 'list-menu',
|
||||
component: ListMenuComponent,
|
||||
data: {
|
||||
title: "Menu Lists",
|
||||
breadcrumb: "Menu Lists"
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'create-menu',
|
||||
component: CreateMenuComponent,
|
||||
data: {
|
||||
title: "Create Menu",
|
||||
breadcrumb: "Create Menu"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class MenusRoutingModule { }
|
||||
@@ -0,0 +1,21 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
// import { NgxDatatableModule } from '@swimlane/ngx-datatable';
|
||||
|
||||
import { MenusRoutingModule } from './menus-routing.module';
|
||||
import { ListMenuComponent } from './list-menu/list-menu.component';
|
||||
import { CreateMenuComponent } from './create-menu/create-menu.component';
|
||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { SharedModule } from 'src/app/shared/shared.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [ListMenuComponent, CreateMenuComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
MenusRoutingModule,
|
||||
NgbModule,
|
||||
SharedModule
|
||||
]
|
||||
})
|
||||
export class MenusModule { }
|
||||
@@ -0,0 +1,79 @@
|
||||
<!-- Container-fluid starts-->
|
||||
<div class="container-fluid">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Add Page</h5>
|
||||
</div>
|
||||
<div class="card-body tab2-card">
|
||||
<ul ngbNav #nav="ngbNav" [(activeId)]="active" class="nav-tabs">
|
||||
<li [ngbNavItem]="1">
|
||||
<a ngbNavLink>General</a>
|
||||
<ng-template ngbNavContent>
|
||||
<form [formGroup]="generalForm" class="needs-validation" novalidate="">
|
||||
<h4>General</h4>
|
||||
<div class="form-group row align-items-center">
|
||||
<div class="col-xl-3 col-md-4"><label for="validationCustom0"><span>*</span> Name</label></div>
|
||||
<div class="col-xl-8 col-md-7"><input class="form-control" formControlName="name"
|
||||
id="validationCustom0" type="text" required="">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row editor-label align-items-center">
|
||||
<div class="col-xl-3 col-md-4"><label>Description</label></div>
|
||||
<div class="col-xl-8 col-md-7"><textarea class="w-100" rows="4" formControlName="desc"></textarea></div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-xl-3 col-md-4"><label>Status</label></div>
|
||||
<div class="col-xl-8 col-md-7"><div class="checkbox checkbox-primary">
|
||||
<input id="checkbox-primary-2" formControlName="status" type="checkbox"
|
||||
data-original-title="" title="">
|
||||
<label for="checkbox-primary-2">Enable the Page</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</ng-template>
|
||||
</li>
|
||||
<li [ngbNavItem]="2">
|
||||
<a ngbNavLink>SEO</a>
|
||||
<ng-template ngbNavContent>
|
||||
<form [formGroup]="seoForm" class="needs-validation" novalidate="">
|
||||
<h4>SEO</h4>
|
||||
<div class="form-group row">
|
||||
<div class="col-xl-3 col-md-4"><label for="validationCustom2">Meta Title</label></div>
|
||||
<div class="col-xl-8 col-md-7"><input class="form-control" formControlName="title"
|
||||
id="validationCustom2" type="text" required=""></div>
|
||||
</div>
|
||||
<div class="form-group row align-items-center editor-label">
|
||||
<div class="col-xl-3 col-md-4"><label>Meta Description</label></div>
|
||||
<div class="col-xl-8 col-md-7"><textarea rows="4" class="w-100" formControlName="meta_desc"></textarea></div>
|
||||
</div>
|
||||
</form>
|
||||
</ng-template>
|
||||
</li>
|
||||
<!-- <li [ngbNavItem]="3">
|
||||
<a ngbNavLink>Usage</a>
|
||||
<ng-template ngbNavContent>
|
||||
<form [formGroup]="usageForm" class="needs-validation" novalidate="">
|
||||
<h4>Usage Limits</h4>
|
||||
<div class="form-group row">
|
||||
<label for="validationCustom6" class="col-xl-3 col-md-4">Per Limit</label>
|
||||
<input class="form-control col-md-7" formControlName="limit" id="validationCustom6"
|
||||
type="number">
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="validationCustom7" class="col-xl-3 col-md-4">Per Customer</label>
|
||||
<input class="form-control col-md-7" formControlName="customer" id="validationCustom7"
|
||||
type="number">
|
||||
</div>
|
||||
</form>
|
||||
</ng-template>
|
||||
</li> -->
|
||||
</ul>
|
||||
<div [ngbNavOutlet]="nav" class="mt-2"></div>
|
||||
<div class="pull-right">
|
||||
<button type="button" class="btn btn-primary">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Container-fluid Ends-->
|
||||
@@ -0,0 +1,37 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'app-create-page',
|
||||
templateUrl: './create-page.component.html',
|
||||
styleUrls: ['./create-page.component.scss']
|
||||
})
|
||||
export class CreatePageComponent implements OnInit {
|
||||
public generalForm: UntypedFormGroup;
|
||||
public seoForm: UntypedFormGroup;
|
||||
public active = 1;
|
||||
|
||||
constructor(private formBuilder: UntypedFormBuilder) {
|
||||
this.createGeneralForm();
|
||||
this.createSeoForm();
|
||||
}
|
||||
|
||||
createGeneralForm() {
|
||||
this.generalForm = this.formBuilder.group({
|
||||
name: [''],
|
||||
desc: [''],
|
||||
status: ['']
|
||||
})
|
||||
}
|
||||
createSeoForm() {
|
||||
this.seoForm = this.formBuilder.group({
|
||||
title: [''],
|
||||
keyword: [''],
|
||||
meta_desc: ['']
|
||||
})
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<!-- Container-fluid starts-->
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Page Details</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="custom-datatable">
|
||||
<button class="btn btn-primary me-1 mb-3" style="float: right;">Delete</button>
|
||||
<div class="clearfix"></div>
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th> </th>
|
||||
<th scope="col" sortable="name" (sort)="onSort($event)">Name</th>
|
||||
<th scope="col" sortable="status" (sort)="onSort($event)">Status</th>
|
||||
<th scope="col" sortable="created_on" (sort)="onSort($event)">Created On</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let item of tableItem$ | async ">
|
||||
<th> <input type="checkbox" name="title_select" onclick="onSelect(item.id)"></th>
|
||||
<th scope="row">
|
||||
{{ item.name }}</th>
|
||||
<td><i class="fa fa-circle {{item.status}} f-12"></i></td>
|
||||
<td>{{item.created_on}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="d-flex justify-content-center p-2">
|
||||
<ngb-pagination
|
||||
[collectionSize]="(total$ | async)!" [(page)]="service.page" [pageSize]="service.pageSize">
|
||||
</ngb-pagination>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Container-fluid Ends-->
|
||||
@@ -0,0 +1,49 @@
|
||||
import { DecimalPipe } from '@angular/common';
|
||||
import { Component, OnInit, QueryList, ViewChildren } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { NgbdSortableHeader, SortEvent } from 'src/app/shared/directives/NgbdSortableHeader';
|
||||
import { TableService } from 'src/app/shared/service/table.service';
|
||||
import { LISTPAGEDB, ListPagesDB } from 'src/app/shared/tables/list-pages';
|
||||
|
||||
@Component({
|
||||
selector: 'app-list-page',
|
||||
templateUrl: './list-page.component.html',
|
||||
styleUrls: ['./list-page.component.scss'],
|
||||
providers: [TableService, DecimalPipe]
|
||||
})
|
||||
export class ListPageComponent implements OnInit {
|
||||
public selected = [];
|
||||
public tableItem$: Observable<ListPagesDB[]>;
|
||||
public searchText;
|
||||
total$: Observable<number>;
|
||||
|
||||
constructor(public service: TableService) {
|
||||
this.tableItem$ = service.tableItem$;
|
||||
this.total$ = service.total$;
|
||||
this.service.setUserData(LISTPAGEDB)
|
||||
}
|
||||
|
||||
@ViewChildren(NgbdSortableHeader) headers: QueryList<NgbdSortableHeader>;
|
||||
|
||||
onSort({ column, direction }: SortEvent) {
|
||||
// resetting other headers
|
||||
this.headers.forEach((header) => {
|
||||
if (header.sortable !== column) {
|
||||
header.direction = '';
|
||||
}
|
||||
});
|
||||
|
||||
this.service.sortColumn = column;
|
||||
this.service.sortDirection = direction;
|
||||
|
||||
}
|
||||
|
||||
onSelect({ selected }) {
|
||||
this.selected.splice(0, this.selected.length);
|
||||
this.selected.push(...selected);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import { NgModule, Component } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
import { ListPageComponent } from './list-page/list-page.component';
|
||||
import { CreatePageComponent } from './create-page/create-page.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
children: [
|
||||
{
|
||||
path: 'list-page',
|
||||
component: ListPageComponent,
|
||||
data: {
|
||||
title: "List Page",
|
||||
breadcrumb: "List Page"
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'create-page',
|
||||
component: CreatePageComponent,
|
||||
data: {
|
||||
title: "Create Page",
|
||||
breadcrumb: "Create Page"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class PagesRoutingModule { }
|
||||
@@ -0,0 +1,21 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { PagesRoutingModule } from './pages-routing.module';
|
||||
import { ListPageComponent } from './list-page/list-page.component';
|
||||
import { CreatePageComponent } from './create-page/create-page.component';
|
||||
import { SharedModule } from 'src/app/shared/shared.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [ListPageComponent, CreatePageComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
PagesRoutingModule,
|
||||
NgbModule,
|
||||
ReactiveFormsModule,
|
||||
SharedModule
|
||||
]
|
||||
})
|
||||
export class PagesModule { }
|
||||
@@ -0,0 +1,108 @@
|
||||
<div class="container-fluid">
|
||||
<div class="row product-adding">
|
||||
<div class="col-xl-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>General</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="digital-add needs-validation">
|
||||
<div class="form-group">
|
||||
<label for="validationCustom01" class="col-form-label pt-0"><span>*</span> Title</label>
|
||||
<input class="form-control" id="validationCustom01" type="text" required="">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="validationCustomtitle" class="col-form-label pt-0"><span>*</span> SKU</label>
|
||||
<input class="form-control" id="validationCustomtitle" type="text" required="">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-form-label"><span>*</span> Categories</label>
|
||||
<select class="custom-select form-select" required="">
|
||||
<option value="">--Select--</option>
|
||||
<option value="1">eBooks</option>
|
||||
<option value="2">Graphic Design</option>
|
||||
<option value="3">3D Impact</option>
|
||||
<option value="4">Application</option>
|
||||
<option value="5">Websites</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-form-label">Sort Summary</label>
|
||||
<textarea rows="5" cols="12"></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="validationCustom02" class="col-form-label"><span>*</span> Product Price</label>
|
||||
<input class="form-control" id="validationCustom02" type="text" required="">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-form-label"><span>*</span> Status</label>
|
||||
<div class="m-checkbox-inline mb-0 custom-radio-ml d-flex radio-animated">
|
||||
<label class="d-block" for="edo-ani">
|
||||
<input class="radio_animated" id="edo-ani" type="radio" name="rdo-ani">
|
||||
Enable
|
||||
</label>
|
||||
<label class="d-block" for="edo-ani1">
|
||||
<input class="radio_animated" id="edo-ani1" type="radio" name="rdo-ani">
|
||||
Disable
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<label class="col-form-label pt-0"> Product Upload</label>
|
||||
<div class="card-body dropzone-custom p-0">
|
||||
<ngx-dropzone class="dropzone-border" (change)="onSelect($event)">
|
||||
<ngx-dropzone-label>
|
||||
<div class="dz-message needsclick">
|
||||
<i class="fa fa-cloud-upload"></i>
|
||||
<h4 class="mb-0 f-w-600">Drop files here or click to upload.</h4>
|
||||
</div>
|
||||
</ngx-dropzone-label>
|
||||
<ngx-dropzone-preview *ngFor="let f of files" [removable]="true" (removed)="onRemove(f)">
|
||||
<ngx-dropzone-label>{{ f.name }} ({{ f.type }})</ngx-dropzone-label>
|
||||
</ngx-dropzone-preview>
|
||||
</ngx-dropzone>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-6">
|
||||
<div class="card h-auto">
|
||||
<div class="card-header">
|
||||
<h5>Add Description</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="digital-add needs-validation">
|
||||
<div class="form-group mb-0">
|
||||
<div class="description-sm">
|
||||
<ckeditor [editor]="Editor" data="<p>Hello, world!</p>"></ckeditor>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Meta Data</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="digital-add needs-validation">
|
||||
<div class="form-group">
|
||||
<label for="validationCustom05" class="col-form-label pt-0"> Meta Title</label>
|
||||
<input class="form-control" id="validationCustom05" type="text" required="">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-form-label">Meta Description</label>
|
||||
<textarea rows="4" cols="12"></textarea>
|
||||
</div>
|
||||
<div class="form-group mb-0">
|
||||
<div class="product-buttons text-end mt-3">
|
||||
<button type="button" class="btn btn-primary">Add</button>
|
||||
<button type="button" class="btn btn-light">Discard</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user