Merge remote-tracking branch 'origin/khue-dev' into dat-dev

This commit is contained in:
Nguyễn Đức Đạt
2023-04-26 18:37:00 +07:00
41 changed files with 440 additions and 1010 deletions
+57
View File
@@ -29,6 +29,7 @@
"@ng-bootstrap/ng-bootstrap": "^13.1.1",
"@popperjs/core": "^2.11.6",
"@swimlane/ngx-charts": "^20.1.0",
"@vercel/analytics": "^1.0.0",
"ag-grid-angular": "^27.3.0",
"ag-grid-community": "^27.3.0",
"angular-count-to": "0.0.3",
@@ -4765,6 +4766,14 @@
"@types/node": "*"
}
},
"node_modules/@vercel/analytics": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@vercel/analytics/-/analytics-1.0.0.tgz",
"integrity": "sha512-RQmj7pv82JwGDHrnKeRc6TtSw2U7rWNubc2IH0ernTzWTj02yr9zvIYiYJeztsBzrJtWv7m8Nz6vxxb+cdEtJw==",
"peerDependencies": {
"react": "^16.8||^17||^18"
}
},
"node_modules/@webassemblyjs/ast": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz",
@@ -10212,6 +10221,18 @@
"resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
"integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA=="
},
"node_modules/loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
"peer": true,
"dependencies": {
"js-tokens": "^3.0.0 || ^4.0.0"
},
"bin": {
"loose-envify": "cli.js"
}
},
"node_modules/lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
@@ -12581,6 +12602,18 @@
"node": ">= 0.8"
}
},
"node_modules/react": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
"integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
"peer": true,
"dependencies": {
"loose-envify": "^1.1.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/read-package-json": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-6.0.0.tgz",
@@ -18735,6 +18768,12 @@
"@types/node": "*"
}
},
"@vercel/analytics": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@vercel/analytics/-/analytics-1.0.0.tgz",
"integrity": "sha512-RQmj7pv82JwGDHrnKeRc6TtSw2U7rWNubc2IH0ernTzWTj02yr9zvIYiYJeztsBzrJtWv7m8Nz6vxxb+cdEtJw==",
"requires": {}
},
"@webassemblyjs/ast": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz",
@@ -22987,6 +23026,15 @@
"resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
"integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA=="
},
"loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
"peer": true,
"requires": {
"js-tokens": "^3.0.0 || ^4.0.0"
}
},
"lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
@@ -24770,6 +24818,15 @@
"unpipe": "1.0.0"
}
},
"react": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
"integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
"peer": true,
"requires": {
"loose-envify": "^1.1.0"
}
},
"read-package-json": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-6.0.0.tgz",
+1
View File
@@ -32,6 +32,7 @@
"@ng-bootstrap/ng-bootstrap": "^13.1.1",
"@popperjs/core": "^2.11.6",
"@swimlane/ngx-charts": "^20.1.0",
"@vercel/analytics": "^1.0.0",
"ag-grid-angular": "^27.3.0",
"ag-grid-community": "^27.3.0",
"angular-count-to": "0.0.3",
-7
View File
@@ -11,12 +11,9 @@ 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 { AccountModule } from './components/account/account.module';
import { SettingModule } from './components/setting/setting.module';
import { ReportsModule } from './components/reports/reports.module';
@@ -43,14 +40,10 @@ import { AuthInterceptor } from "./shared/inceptor/auth-interceptor";
ReportsModule,
AuthModule,
SharedModule,
LocalizationModule,
ProductsModule,
SalesModule,
// NgImageSliderModule,
VendorsModule,
CouponsModule,
PagesModule,
MediaModule,
MenusModule,
UsersModule,
AgGridModule,
+5 -1
View File
@@ -1,5 +1,7 @@
import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import { environment } from "../../../environments/environment";
import firebase from 'firebase/compat/app';
import { AuthRoutingModule } from "./auth-routing.module";
import { LoginComponent } from "./login/login.component";
@@ -15,6 +17,8 @@ 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';
firebase.initializeApp(environment.firebaseConfig);
@NgModule({
declarations: [LoginComponent, SignupComponent, ForbiddenComponent, ResetPasswordComponent, SendEmailComponent, EmailVerifiedComponent, EmailNotVerifiedComponent],
imports: [
@@ -24,6 +28,6 @@ import { EmailNotVerifiedComponent } from './email-not-verified/email-not-verifi
CarouselModule,
SharedModule,
NgbModule,
FormsModule],
FormsModule]
})
export class AuthModule { }
@@ -147,13 +147,15 @@
<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"
<input style="font-family: Metrophobic;" 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"
<input style="font-family: Metrophobic;"
formControlName="password" class="input-password"
type="{{ showPassword ? 'text' : 'password' }}" #pwc
placeholder="Xác nhận mật khẩu" />
<span class="icon-holder-eye"
@@ -167,7 +169,8 @@
formControlName="password"> -->
</div>
<div class="form-button d-flex justify-content-end">
<button class="btn btn-primary w-100 mt-0" type="submit"
<button style="font-family: Metrophobic;"
class="btn btn-primary w-100 mt-0" type="submit"
(click)="onSignIn()">Đăng nhập</button>
</div>
<div class="form-terms mt-1">
@@ -21,12 +21,12 @@
</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)">
<button style="font-family: Metrophobic;" *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)">
<button style="font-family: Metrophobic;" *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"
@@ -44,7 +44,8 @@
<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" />
<input style="font-family: Metrophobic;" 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
@@ -61,7 +62,8 @@
<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" />
<input style="font-family: Metrophobic;" 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
@@ -78,7 +80,8 @@
<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" />
<input style="font-family: Metrophobic;" 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ỏ
@@ -92,9 +95,9 @@
<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 class="col-xl-4 col-md-7">
<input style="font-family: Metrophobic;" 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ỏ
@@ -103,6 +106,25 @@
đa 10 số</div>
</div>
</div>
<div class="col-xl-2 col-md-4">
<button style="font-family: Metrophobic;" type="button" class="btn btn-secondary"
(click)="getOTP()">Gửi OTP</button>
</div>
<div class="col-xl-2 col-md-7">
<input style="font-family: Metrophobic;" formControlName="otp" class="form-control" type="tel"
placeholder="Mã OTP" />
</div>
</div>
<!-- phone number -->
<div class="form-group row">
<div class="col-xl-3 col-md-4">
<label for="validationCustom2"><span></span></label>
</div>
<div class="col-xl-8 col-md-7">
<div id="recapcha">
</div>
</div>
</div>
<!-- identified code -->
@@ -111,8 +133,8 @@
<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" />
<input style="font-family: Metrophobic;" formControlName="identifiedCode" class="form-control"
type="number" placeholder="CMND/CCCD" />
<div
*ngIf="userIdentifiedCode?.invalid && (userIdentifiedCode?.dirty || userIdentifiedCode?.touched)"
class="alert alert-danger mt-1">
@@ -123,14 +145,15 @@
</div>
</div>
</div>
<!-- Address -->
<div class="form-group row">
<div class="col-xl-3 col-md-4">
<label for="validationCustom2"><span>*</span>Địa chỉ</label>
<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ỉ" />
<input style="font-family: Metrophobic;" 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ỏ
@@ -150,8 +173,10 @@
<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>
<select style="font-family: Metrophobic;" [(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>
@@ -164,12 +189,12 @@
</div>
<!-- Wards -->
<div *ngIf="isHaveDistrict" class="form-group row">
<div 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">
<select style="font-family: Metrophobic;" [(ngModel)]="ward" class="form-control">
<option [ngValue]="'none'">--- Chọn phường ---</option>
<option *ngFor="let ward of wards">{{ ward.name }}
</option>
@@ -189,7 +214,7 @@
</div>
<div class="col-xl-8 col-md-7">
<div class="form-control input-password-holder">
<input formControlName="password" class="input-password"
<input style="font-family: Metrophobic;" 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>
@@ -216,8 +241,9 @@
</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" />
<input style="font-family: Metrophobic;" 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>
@@ -272,11 +298,11 @@
</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
<button style="font-family: Metrophobic;" *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>
<button style="font-family: Metrophobic;" *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>
@@ -295,7 +321,8 @@
<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" />
<input style="font-family: Metrophobic;" 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>
@@ -311,8 +338,8 @@
<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>
<textarea style="font-family: Metrophobic;" 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">
@@ -329,10 +356,12 @@
<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
<button style="font-family: Metrophobic;" *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
<button style="font-family: Metrophobic;" *ngIf="!isStudent" type="button"
class="btn btn-primary" (click)="swap()">Shop
thường
</button>
</div>
@@ -345,8 +374,10 @@
</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>
<button style="font-family: Metrophobic;" type="button" class="btn btn-danger mr-3"
(click)="goBackToLogin()">Quay lại</button>
<button style="font-family: Metrophobic;" type="submit" class="btn btn-primary"
(click)="createUser(createSuccess)">Tạo tài khoản</button>
</div>
</div>
</div>
@@ -372,7 +403,8 @@
<ng-template #createSuccess>
<div class="modal-body text-center">
<h5 class="text-dark font-weight-bold mb-4">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</h5>
<h5 class="text-dark font-weight-bold mb-4">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</h5>
<button type="button" class="btn btn-primary" (click)="continue()">Tiếp tục
</button>
</div>
@@ -383,4 +415,19 @@
<h5>{{ errorItem }} đã tồn tại. Vui lòng chọn một {{ errorItem.toLowerCase() }} khác.</h5>
<button type="button" class="btn btn-primary" (click)="closeLayer2()">Tiếp tục</button>
</div>
</ng-template>
<ng-template #miss_otp>
<div class="modal-body text-center">
<h5>Mã OTP trống hoặc không đúng. Vui lòng kiểm tra lại</h5>
<button type="button" class="btn btn-primary" (click)="closeLayer2()">Tiếp tục</button>
</div>
</ng-template>
<ng-template #miss_info>
<div class="modal-body text-center">
<h5>Vui lòng điền đầy đủ thông tin trước khi tạo tài khoản.</h5>
<button type="button" class="btn btn-primary" (click)="closeLayer2()">Tiếp tục</button>
</div>
</ng-template>
@@ -1,5 +1,5 @@
.backgound-food {
background-image: url('../../../../assets/images/background-login.jpg');
background-image: url('../../../../assets/images/resize-bg.png');
width: 100vw;
height: 100%;
background-position: center;
@@ -23,14 +23,16 @@
}
.input-password-holder {
display: flex;
justify-content: space-between;
align-items: center;
.input-password {
border: none;
width: 100%;
}
.icon-holder-eye {
color: #999a9b;
}
}
display: flex;
justify-content: space-between;
align-items: center;
.input-password {
border: none;
width: 100%;
}
.icon-holder-eye {
color: #999a9b;
}
}
+174 -105
View File
@@ -1,5 +1,9 @@
import { Component, TemplateRef, ViewChild } from "@angular/core";
import { AngularFireAuth } from "@angular/fire/compat/auth";
import { AngularFireStorage } from "@angular/fire/compat/storage";
import firebase from 'firebase/compat/app';
import 'firebase/compat/auth';
import 'firebase/compat/firestore';
import { FormBuilder, FormControl, FormGroup, Validators } from "@angular/forms";
import { Router } from "@angular/router";
import { BsModalRef, BsModalService } from "ngx-bootstrap/modal";
@@ -10,7 +14,6 @@ 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";
@@ -64,11 +67,18 @@ export class SignupComponent {
layer1: BsModalRef;
layer2: BsModalRef;
@ViewChild('error_modal') errorModal: TemplateRef<any>;
@ViewChild('miss_info') missInfoModal: TemplateRef<any>;
@ViewChild('miss_otp') missOTPModal: TemplateRef<any>;
//Phonenumber
isVerified: boolean = false;
reCaptchaVerifier;
verify;
constructor(
private formBuilder: FormBuilder,
private authService: AuthService,
private userService: UserService,
private firebaseAuth: AngularFireAuth,
private districtService: DistrictService,
private storage: AngularFireStorage,
private shopService: ShopService,
@@ -87,6 +97,7 @@ export class SignupComponent {
email: new FormControl("", [Validators.required, Validators.email]),
dateOfBirth: new FormControl("", [Validators.required]),
phoneNumber: new FormControl("", [Validators.required, Validators.pattern(Validation.Regex.Phone)]),
otp: new FormControl("", [Validators.required]),
identifiedCode: new FormControl("", [Validators.required, Validators.pattern(Validation.Regex.IdentifiedCode)]),
address: new FormControl("", [Validators.required, Validators.minLength(8)]),
});
@@ -162,6 +173,7 @@ export class SignupComponent {
this.addUserForm.markAllAsTouched();
this.passwordForm.markAllAsTouched();
this.shopForm.markAllAsTouched();
this.layer2 = this.modalService.show(this.missInfoModal, { class: 'modal-sm' });
return Promise.reject();
}
@@ -189,118 +201,170 @@ export class SignupComponent {
return Promise.reject();
}
else {
if (this.userImageChoosen && this.shopImageChoosen) {
this.uploadUserImage(this.userImageFile).then((url) => {
newUser.imageUrl = url
//Check iCode
this.authService.checkIdentifiedCode(this.userIdentifiedCode.value).subscribe((response) => {
if (response.isTrue == false) {
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' })
//Firebase Send Code here
const credential = firebase.auth.PhoneAuthProvider.credential(this.verify, this.otpCode.value);
firebase.auth().signInWithCredential(credential).then((credential) => {
credential.user.delete();
this.isVerified = true;
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' });
}
});
})
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
})
}
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' });
}
})
}
})
).subscribe({
next: () => { },
error: () => {
this.errorItem = 'CCCD/CMND';
this.layer2 = this.modalService.show(this.errorModal, { class: 'modal-sm' });
}
})
}
.catch((error) => {
this.layer2 = this.modalService.show(this.missOTPModal, { class: 'modal-sm' })
return Promise.reject();
})
}
else {
this.errorItem = 'CCCD/CMND';
this.layer2 = this.modalService.show(this.errorModal, { class: 'modal-sm' });
}
})
}
})
}
getOTP() {
this.reCaptchaVerifier = new firebase.auth.RecaptchaVerifier(
'recapcha',
{
size: 'visible',
}
);
firebase
.auth()
.signInWithPhoneNumber('+84 ' + this.userPhoneNumber.value, this.reCaptchaVerifier)
.then((confirmationResult) => {
this.verify = confirmationResult.verificationId;
console.log("send code!");
})
.catch((error) => {
//Catch error
console.log(error.message);
alert(error.message);
setTimeout(() => {
window.location.reload();
}, 5000);
});
}
//Districts and Wards
getAllDistrict() {
this.districtService.getAllDistricts().subscribe((distrs) => {
@@ -310,6 +374,8 @@ export class SignupComponent {
onDistrictSelected() {
this.isHaveDistrict = false;
this.ward = 'none';
this.wards = [];
this.districts.forEach((element: District) => {
if (this.district == element.name && this.district != "Huyện Hoàng Sa") {
this.isHaveDistrict = true;
@@ -441,6 +507,9 @@ export class SignupComponent {
get userPhoneNumber() {
return this.addUserForm.get("phoneNumber");
}
get otpCode() {
return this.addUserForm.get('otp');
}
get userIdentifiedCode() {
return this.addUserForm.get("identifiedCode");
}
@@ -1,39 +0,0 @@
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 { }
@@ -1,21 +0,0 @@
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 { }
@@ -1,46 +0,0 @@
<!-- 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>&nbsp;
<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-->
@@ -1,46 +0,0 @@
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() {
}
}
@@ -1,46 +0,0 @@
<!-- 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>&nbsp;
<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-->
@@ -1,43 +0,0 @@
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() {
}
}
@@ -1,51 +0,0 @@
<!-- 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>&nbsp;
<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-->
@@ -1,45 +0,0 @@
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() {
}
}
@@ -1,25 +0,0 @@
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 { }
-21
View File
@@ -1,21 +0,0 @@
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 { }
@@ -1,67 +0,0 @@
<!-- 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>&nbsp;
<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-->
@@ -1,55 +0,0 @@
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() {
}
}
@@ -1,79 +0,0 @@
<!-- 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-->
@@ -1,37 +0,0 @@
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() {
}
}
@@ -1,43 +0,0 @@
<!-- 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-->
@@ -1,49 +0,0 @@
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() {
}
}
@@ -1,34 +0,0 @@
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 { }
-21
View File
@@ -1,21 +0,0 @@
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 { }
@@ -8,10 +8,10 @@
</div> -->
<div class="card-body">
<div class="custom-datatable">
<div class="mb-3">
<!-- <div class="mb-3">
<input type="text" [(ngModel)]="searchName" (change)="searchOrder()"
class="filter-ngx form-control" placeholder="Tìm kiếm ..." autocomplete="off" />
</div>
</div> -->
<table class="table table-striped" *ngIf="orders.length > 0">
<thead>
<tr>
@@ -23,14 +23,15 @@
<th scope="col">Phương thức</th>
<th scope="col">Trạng thái</th>
<th scope="col">Số tiền</th>
<th scope="col"></th>
<!-- <th scope="col"></th> -->
</tr>
</thead>
<tbody>
<tr *ngFor="let order of orders">
<th scope="row">{{ order.orderTrackingNumber }}</th>
<td>{{ order.orderTime }}</td>
<td>{{ order.user.fullName }}</td>
<td><a [routerLink]="['/users/detail', order?.user?.id]">{{ order.user.fullName
}}</a></td>
<td *ngIf="order?.shipper?.user?.fullName != null">{{ order?.shipper?.user?.fullName
}}</td>
<td *ngIf="order?.shipper?.user?.fullName == null"><i style="color: #FF8084;"
@@ -80,7 +81,7 @@
</span>
</td>
<td style="font-size: 16px;">{{ order.total | currency : "VND" }}</td>
<td scope="row">
<!-- <td scope="row">
<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>
@@ -97,7 +98,7 @@
style="cursor: pointer;">
<i class="fa fa-trash-o"></i>
</a>
</td>
</td> -->
</tr>
</tbody>
</table>
@@ -0,0 +1,63 @@
th,
td {
text-align: center;
}
.modal-change-status {
// width: 1000px;
.modal-confirm-text {
text-align: center;
padding: 20px 8px;
font-weight: 600;
}
.modal-select-option {
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 20px;
select {
padding: 12px 20px;
}
}
.modal-btn-option {
width: 100%;
display: flex;
justify-content: space-around;
align-items: center;
padding-bottom: 20px;
.width-btn {
width: 110px;
}
}
}
.modal-confirm-delete {
// width: 1000px;
.modal-confirm-text {
text-align: center;
padding: 20px 8px;
font-weight: 600;
}
.modal-btn-option {
width: 100%;
display: flex;
justify-content: space-around;
align-items: center;
padding-bottom: 20px;
.width-btn {
width: 110px;
}
}
}
.modal-confirm-text {
font-weight: 600;
}
@@ -57,52 +57,13 @@ export class ScamOrdersComponent {
ngOnInit() {
this.userService.getUserByToken(this.token).subscribe((userInfo) => {
this.loggedRole = userInfo.userRole;
if (this.loggedRole != 'ROLE_ADMIN') {
this.isShop = true;
this.shopId = userInfo.shopId
}
this.listOrder();
})
}
listOrder() {
if (this.isShop) {
this.orderService.getOrdersByShopId(this.shopId, this.thePageNumber - 1, this.thePageSize, this.sortBy, this.sortDir)
.subscribe(this.processResult());
this.shipperService.findFreeShopShipper(this.shopId).subscribe((shippers) => {
this.shippers = shippers;
})
}
else {
this.orderService
.getOrdersPagination(this.thePageNumber - 1, this.thePageSize, this.sortBy, this.sortDir)
.subscribe(this.processResult());
}
this.refreshTimeout = setTimeout(() => {
this.refreshOrder();
}, this.refreshInterval);
}
refreshOrder() {
if (this.isShop) {
this.orderService.getOrdersByShopId(this.shopId, this.thePageNumber - 1, this.thePageSize, this.sortBy, this.sortDir)
.subscribe(this.refreshResult());
this.shipperService.findFreeShopShipper(this.shopId).subscribe((shippers) => {
this.shippers = shippers;
})
}
else {
this.orderService
.getOrdersPagination(this.thePageNumber - 1, this.thePageSize, this.sortBy, this.sortDir)
.subscribe(this.refreshResult());
}
this.refreshTimeout = setTimeout(() => {
this.refreshOrder();
}, this.refreshInterval);
this.orderService.findOrderByStatus('REJECT_DELIVERY', this.thePageNumber - 1, this.thePageSize, this.sortBy, this.sortDir)
.subscribe(this.processResult());
}
searchOrder() {
@@ -117,6 +78,7 @@ export class ScamOrdersComponent {
processResult() {
return (data: any) => {
console.log(data)
this.orders = data.orders;
this.thePageNumber = data.page.pageNo + 1;
this.thePageSize = data.page.pageSize;
@@ -125,18 +87,6 @@ export class ScamOrdersComponent {
};
}
refreshResult() {
return (data: any) => {
this.orders = data.orders;
this.thePageNumber = data.page.pageNo + 1;
this.thePageSize = data.page.pageSize;
this.theTotalElements = data.page.totalElements;
if (this.totalOrders != this.theTotalElements) {
this.totalOrders = this.theTotalElements;
}
};
}
// Change status order modal
openStatusModal(confirmBoxChangeStatus: TemplateRef<any>, userId: number, orderId: number, shipper: Shipper) {
this.isHaveShipper = false;
@@ -11,7 +11,7 @@
(change)="searchAddress()" />
</div>
<div id="batchDelete" class="custom-datatable" *ngIf="addresses.length > 0">
<div id="batchDelete" class="custom-datatable" *ngIf="addresses?.length > 0">
<div class="table-responsive">
<table class="table table-striped">
<thead>
+18 -18
View File
@@ -33,17 +33,17 @@ export const content: Routes = [
breadcrumb: "Coupons"
}
},
{
path: 'pages',
loadChildren: () => import('../../components/pages/pages.module').then(m => m.PagesModule),
data: {
breadcrumb: "Pages"
}
},
{
path: 'media',
loadChildren: () => import('../../components/media/media.module').then(m => m.MediaModule),
},
// {
// path: 'pages',
// loadChildren: () => import('../../components/pages/pages.module').then(m => m.PagesModule),
// data: {
// breadcrumb: "Pages"
// }
// },
// {
// path: 'media',
// loadChildren: () => import('../../components/media/media.module').then(m => m.MediaModule),
// },
{
path: 'menus',
loadChildren: () => import('../../components/menus/menus.module').then(m => m.MenusModule),
@@ -65,13 +65,13 @@ export const content: Routes = [
breadcrumb: "Shop"
}
},
{
path: 'localization',
loadChildren: () => import('../../components/localization/localization.module').then(m => m.LocalizationModule),
data: {
breadcrumb: "Localization"
}
},
// {
// path: 'localization',
// loadChildren: () => import('../../components/localization/localization.module').then(m => m.LocalizationModule),
// data: {
// breadcrumb: "Localization"
// }
// },
{
path: 'reports',
loadChildren: () => import('../../components/reports/reports.module').then(m => m.ReportsModule),
+4
View File
@@ -36,6 +36,10 @@ export class AuthService {
return this.httpClient.post<StringBoolObject>(this.baseUrl + `/check`, userDto);
}
checkIdentifiedCode(code: string) {
return this.httpClient.get<StringBoolObject>(this.baseUrl + `/check?code=${code}`);
}
checkEmailInDB(email: string) {
return this.httpClient.get<StringBoolObject>(this.baseUrl + `/check-email?email=${email}`)
}
+1 -1
View File
@@ -50,7 +50,7 @@ export class FirebaseService {
if (!response.user.emailVerified) {
response.user.sendEmailVerification();
this.router.navigate(['/auth/email-not-verified']);
resolve(false); // trả về false nếu email chưa được xác thực
resolve(true); // trả về false nếu email chưa được xác thực
} else {
response.user.getIdToken().then((token: string) => {
this.token = token;
+4
View File
@@ -61,6 +61,10 @@ export class OrderService {
findOrdersByTrackingNumber(trackingNumber: string, thePage: number, thePageSize: number, sortBy: string, sortDir: string) {
return this.httpClient.get<GetResponseOrders>(this.orderUrl + `/search?trackingNumber=${trackingNumber}&pageNo=${thePage}&pageSize=${thePageSize}&sortBy=${sortBy}&sortDir=${sortDir}`);
}
findOrderByStatus(status: string, thePage: number, thePageSize: number, sortBy: string, sortDir: string) {
return this.httpClient.get<GetResponseOrders>(this.orderUrl + `/get?status=${status}`);
}
}
interface GetResponseOrders {
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 MiB