application name, registration and forgot password updates
This commit is contained in:
parent
f9fe0569d3
commit
716f063ecf
@ -1,20 +1,19 @@
|
|||||||
import { Routes } from '@angular/router';
|
import { Routes } from '@angular/router';
|
||||||
import { AppIdGuard } from './guards/appid.guard';
|
import { AppIdGuard } from './guards/appid.guard';
|
||||||
import { AuthGuard } from './guards/auth.guard';
|
import { AuthGuard } from './guards/auth.guard';
|
||||||
import { HomeComponent } from './home/home.component';
|
|
||||||
import { LoginComponent } from './login/login.component';
|
|
||||||
import { NotFoundComponent } from './shared/components/not-found/not-found.component';
|
|
||||||
import { UserSettingsComponent } from './user-settings/user-settings.component';
|
|
||||||
|
|
||||||
export const routes: Routes = [
|
export const routes: Routes = [
|
||||||
{ path: 'login', component: LoginComponent },
|
{ path: 'login', loadComponent: () => import('./login/login.component').then(m => m.LoginComponent) },
|
||||||
{ path: '404', component: NotFoundComponent },
|
{ path: 'forgot-password', loadComponent: () => import('./forgot-password/forgot-password.component').then(m => m.ForgotPasswordComponent) },
|
||||||
|
{ path: 'register/:token', loadComponent: () => import('./register/register.component').then(m => m.RegisterComponent) },
|
||||||
|
{ path: '404', loadComponent: () => import('./shared/components/not-found/not-found.component').then(m => m.NotFoundComponent) },
|
||||||
{
|
{
|
||||||
path: ':appId',
|
path: ':appId',
|
||||||
children: [
|
children: [
|
||||||
{ path: 'home', component: HomeComponent },
|
{ path: 'home', loadComponent: () => import('./home/home.component').then(m => m.HomeComponent) },
|
||||||
{ path: 'usersettings', component: UserSettingsComponent },
|
{ path: 'usersettings', loadComponent: () => import('./user-settings/user-settings.component').then(m => m.UserSettingsComponent) },
|
||||||
{ path: 'add-carnet', loadComponent: () => import('./carnet/add/add-carnet.component').then(m => m.AddCarnetComponent) },
|
{ path: 'add-carnet', loadComponent: () => import('./carnet/add/add-carnet.component').then(m => m.AddCarnetComponent) },
|
||||||
|
{ path: 'edit-carnet/:headerid', loadComponent: () => import('./carnet/edit/edit-carnet.component').then(m => m.EditCarnetComponent) },
|
||||||
{ path: '', redirectTo: 'home', pathMatch: 'full' }
|
{ path: '', redirectTo: 'home', pathMatch: 'full' }
|
||||||
],
|
],
|
||||||
canActivate: [AuthGuard, AppIdGuard]
|
canActivate: [AuthGuard, AppIdGuard]
|
||||||
|
|||||||
@ -1,64 +1,21 @@
|
|||||||
<div class="client-carnet-container">
|
<div class="client-carnet-container">
|
||||||
<!-- Initial Questions Section -->
|
|
||||||
<div *ngIf="!questionsCompleted" class="questions-section">
|
|
||||||
<h2>Add New Carnet</h2>
|
|
||||||
|
|
||||||
<form [formGroup]="questionsForm" (ngSubmit)="onQuestionsSubmit()">
|
|
||||||
<div class="question-row">
|
|
||||||
<mat-radio-group formControlName="newCarnet">
|
|
||||||
<mat-label>Do you need a new carnet?</mat-label>
|
|
||||||
<mat-radio-button [value]="true">Yes</mat-radio-button>
|
|
||||||
<mat-radio-button [value]="false">No</mat-radio-button>
|
|
||||||
</mat-radio-group>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="question-row">
|
|
||||||
<mat-radio-group formControlName="additionalSets">
|
|
||||||
<mat-label>Do you need additional sets?</mat-label>
|
|
||||||
<mat-radio-button [value]="true">Yes</mat-radio-button>
|
|
||||||
<mat-radio-button [value]="false">No</mat-radio-button>
|
|
||||||
</mat-radio-group>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="question-row">
|
|
||||||
<mat-radio-group formControlName="duplicateCarnet">
|
|
||||||
<mat-label>Did you lose your carnet? Are you looking for duplicates?</mat-label>
|
|
||||||
<mat-radio-button [value]="true">Yes</mat-radio-button>
|
|
||||||
<mat-radio-button [value]="false">No</mat-radio-button>
|
|
||||||
</mat-radio-group>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="question-row">
|
|
||||||
<mat-radio-group formControlName="extendCarnet">
|
|
||||||
<mat-label>Do you need to extend the carnet?</mat-label>
|
|
||||||
<mat-radio-button [value]="true">Yes</mat-radio-button>
|
|
||||||
<mat-radio-button [value]="false">No</mat-radio-button>
|
|
||||||
</mat-radio-group>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="actions">
|
|
||||||
<button mat-raised-button color="primary" type="submit" [disabled]="!questionsForm.valid">
|
|
||||||
Continue
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Stepper Section (shown after questions are answered) -->
|
<!-- Stepper Section (shown after questions are answered) -->
|
||||||
<mat-stepper *ngIf="questionsCompleted" orientation="vertical" [linear]="isLinear"
|
<mat-stepper orientation="vertical" [linear]="isLinear" (selectionChange)="onStepChange($event)"
|
||||||
(selectionChange)="onStepChange($event)" [selectedIndex]="currentStep">
|
[selectedIndex]="currentStep">
|
||||||
|
|
||||||
<!-- Application Name Step -->
|
<!-- Application Name Step -->
|
||||||
<mat-step [completed]="stepsCompleted.applicationDetail" [editable]="stepsCompleted.applicationDetail">
|
<mat-step *ngIf="applicationType === 'new'" [completed]="stepsCompleted.applicationDetail"
|
||||||
|
[editable]="stepsCompleted.applicationDetail">
|
||||||
<ng-template matStepLabel>Application Name</ng-template>
|
<ng-template matStepLabel>Application Name</ng-template>
|
||||||
<app-application [isEditMode]="isEditMode" (applicationIdCreated)="onApplicationDetailCreated($event)">
|
<app-application [isEditMode]="isEditMode" (headerIdCreated)="onApplicationDetailCreated($event)">
|
||||||
</app-application>
|
</app-application>
|
||||||
</mat-step>
|
</mat-step>
|
||||||
|
|
||||||
<!-- Holder Selection Step -->
|
<!-- Holder Selection Step -->
|
||||||
<mat-step [completed]="stepsCompleted.holderSelection" [editable]="stepsCompleted.applicationDetail">
|
<mat-step *ngIf="applicationType === 'new'" [completed]="stepsCompleted.holderSelection"
|
||||||
|
[editable]="stepsCompleted.applicationDetail">
|
||||||
<ng-template matStepLabel>Holder Selection</ng-template>
|
<ng-template matStepLabel>Holder Selection</ng-template>
|
||||||
<app-holder (completed)="onHolderSelectionSaved($event)">
|
<app-holder (completed)="onHolderSelectionSaved($event)" [headerid]="headerid">
|
||||||
</app-holder>
|
</app-holder>
|
||||||
</mat-step>
|
</mat-step>
|
||||||
|
|
||||||
@ -66,44 +23,45 @@
|
|||||||
<mat-step *ngIf="applicationType === 'new'" [completed]="stepsCompleted.goodsSection"
|
<mat-step *ngIf="applicationType === 'new'" [completed]="stepsCompleted.goodsSection"
|
||||||
[editable]="stepsCompleted.applicationDetail">
|
[editable]="stepsCompleted.applicationDetail">
|
||||||
<ng-template matStepLabel>Goods Section</ng-template>
|
<ng-template matStepLabel>Goods Section</ng-template>
|
||||||
<app-goods (completed)="onGoodsSectionSaved($event)">
|
<app-goods (completed)="onGoodsSectionSaved($event)" [headerid]="headerid">
|
||||||
</app-goods>
|
</app-goods>
|
||||||
</mat-step>
|
</mat-step>
|
||||||
|
|
||||||
<!-- Travel Plan Step -->
|
<!-- Travel Plan Step -->
|
||||||
<mat-step *ngIf="applicationType === 'new' || applicationType === 'extend'"
|
<mat-step *ngIf="applicationType === 'new' || applicationType === 'extend' || applicationType === 'additional'"
|
||||||
[completed]="stepsCompleted.travelPlan" [editable]="stepsCompleted.applicationDetail">
|
[completed]="stepsCompleted.travelPlan" [editable]="stepsCompleted.applicationDetail">
|
||||||
<ng-template matStepLabel>Travel Plan</ng-template>
|
<ng-template matStepLabel>Travel Plan</ng-template>
|
||||||
<!-- <app-travel-plan (completed)="onTravelPlanSaved($event)">
|
<app-travel-plan (completed)="onTravelPlanSaved($event)" [headerid]="headerid">
|
||||||
</app-travel-plan> -->
|
</app-travel-plan>
|
||||||
</mat-step>
|
</mat-step>
|
||||||
|
|
||||||
<!-- Insurance Step -->
|
<!-- Insurance Step -->
|
||||||
<mat-step [completed]="stepsCompleted.insurance" [editable]="stepsCompleted.applicationDetail">
|
<mat-step *ngIf="applicationType === 'new' || applicationType === 'extend' || applicationType === 'additional'"
|
||||||
|
[completed]="stepsCompleted.insurance" [editable]="stepsCompleted.applicationDetail">
|
||||||
<ng-template matStepLabel>Insurance</ng-template>
|
<ng-template matStepLabel>Insurance</ng-template>
|
||||||
<!-- <app-insurance (completed)="onInsuranceSaved($event)">
|
<app-insurance (completed)="onInsuranceSaved($event)" [headerid]="headerid">
|
||||||
</app-insurance> -->
|
</app-insurance>
|
||||||
</mat-step>
|
</mat-step>
|
||||||
|
|
||||||
<!-- Shipping Step -->
|
<!-- Shipping Step -->
|
||||||
<mat-step [completed]="stepsCompleted.shipping" [editable]="stepsCompleted.applicationDetail">
|
<mat-step [completed]="stepsCompleted.shipping" [editable]="stepsCompleted.applicationDetail">
|
||||||
<ng-template matStepLabel>Shipping</ng-template>
|
<ng-template matStepLabel>Shipping</ng-template>
|
||||||
<!-- <app-shipping (completed)="onShippingSaved($event)">
|
<app-shipping (completed)="onShippingSaved($event)" [headerid]="headerid">
|
||||||
</app-shipping> -->
|
</app-shipping>
|
||||||
</mat-step>
|
</mat-step>
|
||||||
|
|
||||||
<!-- Delivery Method Step -->
|
<!-- Delivery Method Step -->
|
||||||
<mat-step [completed]="stepsCompleted.deliveryMethod" [editable]="stepsCompleted.applicationDetail">
|
<mat-step [completed]="stepsCompleted.deliveryMethod" [editable]="stepsCompleted.applicationDetail">
|
||||||
<ng-template matStepLabel>Delivery Method</ng-template>
|
<ng-template matStepLabel>Delivery Method</ng-template>
|
||||||
<!-- <app-delivery-method (completed)="onDeliveryMethodSaved($event)">
|
<app-delivery (completed)="onDeliveryMethodSaved($event)" [headerid]="headerid">
|
||||||
</app-delivery-method> -->
|
</app-delivery>
|
||||||
</mat-step>
|
</mat-step>
|
||||||
|
|
||||||
<!-- Payment Step -->
|
<!-- Payment Step -->
|
||||||
<mat-step [completed]="stepsCompleted.payment" [editable]="stepsCompleted.applicationDetail">
|
<mat-step [completed]="stepsCompleted.payment" [editable]="stepsCompleted.applicationDetail">
|
||||||
<ng-template matStepLabel>Payment</ng-template>
|
<ng-template matStepLabel>Payment</ng-template>
|
||||||
<!-- <app-payment (completed)="onPaymentSaved($event)">
|
<app-payment (completed)="onPaymentSaved($event)" [headerid]="headerid">
|
||||||
</app-payment> -->
|
</app-payment>
|
||||||
</mat-step>
|
</mat-step>
|
||||||
</mat-stepper>
|
</mat-stepper>
|
||||||
</div>
|
</div>
|
||||||
@ -1,51 +1,11 @@
|
|||||||
.client-carnet-container {
|
// .client-carnet-container {
|
||||||
// padding: 24px;
|
// // padding: 24px;
|
||||||
// max-width: 1200px;
|
// // max-width: 1200px;
|
||||||
// margin: 0 auto;
|
// // margin: 0 auto;
|
||||||
|
|
||||||
.questions-section {
|
// .actions {
|
||||||
// padding: 20px;
|
// margin-top: 24px;
|
||||||
// border-radius: 8px;
|
// display: flex;
|
||||||
// margin-bottom: 24px;
|
// justify-content: flex-start;
|
||||||
|
|
||||||
// h2 {
|
|
||||||
// margin-bottom: 24px;
|
|
||||||
// color: #3f51b5;
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
.question-row {
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
padding: 1rem;
|
|
||||||
background: #ffff;
|
|
||||||
border-radius: 4px;
|
|
||||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
||||||
|
|
||||||
mat-radio-group {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 8px;
|
|
||||||
|
|
||||||
// mat-label {
|
|
||||||
// margin-bottom: 8px;
|
|
||||||
// font-weight: 500;
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
mat-radio-button {
|
|
||||||
margin-right: 1rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.actions {
|
|
||||||
margin-top: 24px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.actions {
|
|
||||||
margin-top: 24px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-start;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -6,31 +6,26 @@ import { StepperSelectionEvent } from '@angular/cdk/stepper';
|
|||||||
import { ApplicationComponent } from "../application/application.component";
|
import { ApplicationComponent } from "../application/application.component";
|
||||||
import { HolderComponent } from '../holder/holder.component';
|
import { HolderComponent } from '../holder/holder.component';
|
||||||
import { GoodsComponent } from '../goods/goods.component';
|
import { GoodsComponent } from '../goods/goods.component';
|
||||||
|
import { TravelPlanComponent } from '../travel-plan/travel-plan.component';
|
||||||
|
import { InsuranceComponent } from '../insurance/insurance.component';
|
||||||
|
import { PaymentComponent } from '../payment/payment.component';
|
||||||
|
import { ShippingComponent } from '../shipping/shipping.component';
|
||||||
|
import { DeliveryComponent } from '../delivery/delivery.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-add-carnet',
|
selector: 'app-add-carnet',
|
||||||
imports: [AngularMaterialModule, CommonModule, ReactiveFormsModule,
|
imports: [AngularMaterialModule, CommonModule, ReactiveFormsModule,
|
||||||
ApplicationComponent, HolderComponent, GoodsComponent],
|
ApplicationComponent, HolderComponent, GoodsComponent, TravelPlanComponent, InsuranceComponent,
|
||||||
|
ShippingComponent, DeliveryComponent, PaymentComponent],
|
||||||
templateUrl: './add-carnet.component.html',
|
templateUrl: './add-carnet.component.html',
|
||||||
styleUrl: './add-carnet.component.scss'
|
styleUrl: './add-carnet.component.scss'
|
||||||
})
|
})
|
||||||
export class AddCarnetComponent {
|
export class AddCarnetComponent {
|
||||||
currentStep = 0;
|
currentStep = 0;
|
||||||
questionsCompleted = false;
|
|
||||||
isLinear = true;
|
isLinear = true;
|
||||||
applicationType: 'new' | 'additional' | 'duplicate' | 'extend' | null = null;
|
applicationType: 'new' | 'additional' | 'duplicate' | 'extend' | null = 'new';
|
||||||
isEditMode = false;
|
isEditMode = false;
|
||||||
applicationid: number = 0;
|
headerid: number = 0;
|
||||||
|
|
||||||
private fb = inject(FormBuilder);
|
|
||||||
|
|
||||||
// Form group for initial questions
|
|
||||||
questionsForm: FormGroup = this.fb.group({
|
|
||||||
newCarnet: [null, Validators.required],
|
|
||||||
additionalSets: [false],
|
|
||||||
duplicateCarnet: [false],
|
|
||||||
extendCarnet: [false]
|
|
||||||
});
|
|
||||||
|
|
||||||
// Track completion of each step
|
// Track completion of each step
|
||||||
stepsCompleted = {
|
stepsCompleted = {
|
||||||
@ -44,30 +39,12 @@ export class AddCarnetComponent {
|
|||||||
payment: false
|
payment: false
|
||||||
};
|
};
|
||||||
|
|
||||||
onQuestionsSubmit(): void {
|
|
||||||
const answers = this.questionsForm.value;
|
|
||||||
|
|
||||||
if (answers.newCarnet) {
|
|
||||||
this.applicationType = 'new';
|
|
||||||
} else if (answers.additionalSets) {
|
|
||||||
this.applicationType = 'additional';
|
|
||||||
} else if (answers.duplicateCarnet) {
|
|
||||||
this.applicationType = 'duplicate';
|
|
||||||
} else if (answers.extendCarnet) {
|
|
||||||
this.applicationType = 'extend';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move to the first step after questions
|
|
||||||
this.questionsCompleted = true;
|
|
||||||
this.currentStep = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
onStepChange(event: StepperSelectionEvent): void {
|
onStepChange(event: StepperSelectionEvent): void {
|
||||||
this.currentStep = event.selectedIndex;
|
this.currentStep = event.selectedIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
onApplicationDetailCreated(applicationid: number): void {
|
onApplicationDetailCreated(headerid: number): void {
|
||||||
this.applicationid = applicationid;
|
this.headerid = this.headerid;
|
||||||
this.stepsCompleted.applicationDetail = true;
|
this.stepsCompleted.applicationDetail = true;
|
||||||
this.isLinear = false; // Disable linear mode after application detail is created
|
this.isLinear = false; // Disable linear mode after application detail is created
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import { ApplicationDetail } from '../../core/models/carnet/application-detail';
|
|||||||
import { Subject } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
import { AngularMaterialModule } from '../../shared/module/angular-material.module';
|
import { AngularMaterialModule } from '../../shared/module/angular-material.module';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-application',
|
selector: 'app-application',
|
||||||
@ -16,9 +17,10 @@ import { CommonModule } from '@angular/common';
|
|||||||
})
|
})
|
||||||
export class ApplicationComponent {
|
export class ApplicationComponent {
|
||||||
@Input() isEditMode = false;
|
@Input() isEditMode = false;
|
||||||
@Input() applicationid: number = 0;
|
@Input() headerid: number = 0;
|
||||||
|
@Input() applicationName: string = '';
|
||||||
|
|
||||||
@Output() applicationIdCreated = new EventEmitter<number>();
|
@Output() headerIdCreated = new EventEmitter<number>();
|
||||||
|
|
||||||
applicationDetailsForm: FormGroup;
|
applicationDetailsForm: FormGroup;
|
||||||
isLoading = false;
|
isLoading = false;
|
||||||
@ -30,31 +32,33 @@ export class ApplicationComponent {
|
|||||||
private applicationDetailService = inject(ApplicationDetailService);
|
private applicationDetailService = inject(ApplicationDetailService);
|
||||||
private notificationService = inject(NotificationService);
|
private notificationService = inject(NotificationService);
|
||||||
private errorHandler = inject(ApiErrorHandlerService);
|
private errorHandler = inject(ApiErrorHandlerService);
|
||||||
|
private route = inject(ActivatedRoute);
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.applicationDetailsForm = this.createForm();
|
this.applicationDetailsForm = this.createForm();
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
// this.spidCreated.emit(this.spid?.toString());
|
this.applicationName = this.route.snapshot.queryParamMap.get('applicationName') || '';
|
||||||
|
|
||||||
// Patch edit form data
|
// Patch edit form data
|
||||||
if (this.applicationid > 0) {
|
if (this.applicationName) {
|
||||||
this.isLoading = true;
|
this.patchFormData();
|
||||||
this.applicationDetailService.getApplicationDetailsById(this.applicationid).subscribe({
|
|
||||||
next: (applicationDetail: ApplicationDetail) => {
|
// this.applicationDetailService.getApplicationDetailsById(this.headerid).subscribe({
|
||||||
if (applicationDetail?.applicationId > 0) {
|
// next: (applicationDetail: ApplicationDetail) => {
|
||||||
this.patchFormData(applicationDetail);
|
// if (applicationDetail?.applicationId > 0) {
|
||||||
}
|
// this.patchFormData(applicationDetail);
|
||||||
this.isLoading = false;
|
// }
|
||||||
},
|
// this.isLoading = false;
|
||||||
error: (error: any) => {
|
// },
|
||||||
let errorMessage = this.errorHandler.handleApiError(error, 'Failed to load application details');
|
// error: (error: any) => {
|
||||||
this.notificationService.showError(errorMessage);
|
// let errorMessage = this.errorHandler.handleApiError(error, 'Failed to load application details');
|
||||||
this.isLoading = false;
|
// this.notificationService.showError(errorMessage);
|
||||||
console.error('Error loading application details:', error);
|
// this.isLoading = false;
|
||||||
}
|
// console.error('Error loading application details:', error);
|
||||||
});
|
// }
|
||||||
|
// });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,9 +73,9 @@ export class ApplicationComponent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
patchFormData(data: ApplicationDetail): void {
|
patchFormData(): void {
|
||||||
this.applicationDetailsForm.patchValue({
|
this.applicationDetailsForm.patchValue({
|
||||||
name: data.name,
|
name: this.applicationName,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.isEditMode) {
|
if (this.isEditMode) {
|
||||||
@ -93,12 +97,12 @@ export class ApplicationComponent {
|
|||||||
|
|
||||||
const applicationDetailData: ApplicationDetail = this.applicationDetailsForm.value;
|
const applicationDetailData: ApplicationDetail = this.applicationDetailsForm.value;
|
||||||
|
|
||||||
if (!this.isEditMode && this.applicationid == 0) {
|
if (!this.isEditMode && this.headerid == 0) {
|
||||||
this.isLoading = true;
|
this.isLoading = true;
|
||||||
this.applicationDetailService.createApplicationDetails(applicationDetailData).subscribe({
|
this.applicationDetailService.createApplicationDetails(applicationDetailData).subscribe({
|
||||||
next: (applicationData: any) => {
|
next: (applicationData: any) => {
|
||||||
this.notificationService.showSuccess(`Application details added successfully`);
|
this.notificationService.showSuccess(`Application details added successfully`);
|
||||||
this.applicationIdCreated.emit(applicationData.P_HEADERID);
|
this.headerIdCreated.emit(applicationData.P_HEADERID);
|
||||||
this.applicationDetailsForm.get('name')?.disable();
|
this.applicationDetailsForm.get('name')?.disable();
|
||||||
this.disableSaveButton = true;
|
this.disableSaveButton = true;
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
|
|||||||
@ -1 +0,0 @@
|
|||||||
<p>delivery works!</p>
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-delivery',
|
selector: 'app-delivery',
|
||||||
@ -7,5 +7,7 @@ import { Component } from '@angular/core';
|
|||||||
styleUrl: './delivery.component.scss'
|
styleUrl: './delivery.component.scss'
|
||||||
})
|
})
|
||||||
export class DeliveryComponent {
|
export class DeliveryComponent {
|
||||||
|
@Input() headerid: number = 0;
|
||||||
|
@Output() completed = new EventEmitter<boolean>();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1 +1,67 @@
|
|||||||
<p>edit-carnet works!</p>
|
<div class="client-carnet-container">
|
||||||
|
<!-- Stepper Section (shown after questions are answered) -->
|
||||||
|
<mat-stepper orientation="vertical" [linear]="isLinear" (selectionChange)="onStepChange($event)"
|
||||||
|
[selectedIndex]="currentStep">
|
||||||
|
|
||||||
|
<!-- Application Name Step -->
|
||||||
|
<mat-step *ngIf="applicationType === 'new'" [completed]="stepsCompleted.applicationDetail"
|
||||||
|
[editable]="stepsCompleted.applicationDetail">
|
||||||
|
<ng-template matStepLabel>Application Name</ng-template>
|
||||||
|
<app-application [isEditMode]="isEditMode">
|
||||||
|
</app-application>
|
||||||
|
</mat-step>
|
||||||
|
|
||||||
|
<!-- Holder Selection Step -->
|
||||||
|
<mat-step *ngIf="applicationType === 'new'" [completed]="stepsCompleted.holderSelection"
|
||||||
|
[editable]="stepsCompleted.applicationDetail">
|
||||||
|
<ng-template matStepLabel>Holder Selection</ng-template>
|
||||||
|
<app-holder (completed)="onHolderSelectionSaved($event)" [headerid]="headerid">
|
||||||
|
</app-holder>
|
||||||
|
</mat-step>
|
||||||
|
|
||||||
|
<!-- Goods Section Step -->
|
||||||
|
<mat-step *ngIf="applicationType === 'new'" [completed]="stepsCompleted.goodsSection"
|
||||||
|
[editable]="stepsCompleted.applicationDetail">
|
||||||
|
<ng-template matStepLabel>Goods Section</ng-template>
|
||||||
|
<app-goods (completed)="onGoodsSectionSaved($event)" [headerid]="headerid">
|
||||||
|
</app-goods>
|
||||||
|
</mat-step>
|
||||||
|
|
||||||
|
<!-- Travel Plan Step -->
|
||||||
|
<mat-step *ngIf="applicationType === 'new' || applicationType === 'extend' || applicationType === 'additional'"
|
||||||
|
[completed]="stepsCompleted.travelPlan" [editable]="stepsCompleted.applicationDetail">
|
||||||
|
<ng-template matStepLabel>Travel Plan</ng-template>
|
||||||
|
<app-travel-plan (completed)="onTravelPlanSaved($event)" [headerid]="headerid">
|
||||||
|
</app-travel-plan>
|
||||||
|
</mat-step>
|
||||||
|
|
||||||
|
<!-- Insurance Step -->
|
||||||
|
<mat-step *ngIf="applicationType === 'new' || applicationType === 'extend' || applicationType === 'additional'"
|
||||||
|
[completed]="stepsCompleted.insurance" [editable]="stepsCompleted.applicationDetail">
|
||||||
|
<ng-template matStepLabel>Insurance</ng-template>
|
||||||
|
<app-insurance (completed)="onInsuranceSaved($event)" [headerid]="headerid">
|
||||||
|
</app-insurance>
|
||||||
|
</mat-step>
|
||||||
|
|
||||||
|
<!-- Shipping Step -->
|
||||||
|
<mat-step [completed]="stepsCompleted.shipping" [editable]="stepsCompleted.applicationDetail">
|
||||||
|
<ng-template matStepLabel>Shipping</ng-template>
|
||||||
|
<app-shipping (completed)="onShippingSaved($event)" [headerid]="headerid">
|
||||||
|
</app-shipping>
|
||||||
|
</mat-step>
|
||||||
|
|
||||||
|
<!-- Delivery Method Step -->
|
||||||
|
<mat-step [completed]="stepsCompleted.deliveryMethod" [editable]="stepsCompleted.applicationDetail">
|
||||||
|
<ng-template matStepLabel>Delivery Method</ng-template>
|
||||||
|
<app-delivery (completed)="onDeliveryMethodSaved($event)" [headerid]="headerid">
|
||||||
|
</app-delivery>
|
||||||
|
</mat-step>
|
||||||
|
|
||||||
|
<!-- Payment Step -->
|
||||||
|
<mat-step [completed]="stepsCompleted.payment" [editable]="stepsCompleted.applicationDetail">
|
||||||
|
<ng-template matStepLabel>Payment</ng-template>
|
||||||
|
<app-payment (completed)="onPaymentSaved($event)" [headerid]="headerid">
|
||||||
|
</app-payment>
|
||||||
|
</mat-step>
|
||||||
|
</mat-stepper>
|
||||||
|
</div>
|
||||||
@ -1,11 +1,81 @@
|
|||||||
import { Component } from '@angular/core';
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { Component, inject } from '@angular/core';
|
||||||
|
import { AngularMaterialModule } from '../../shared/module/angular-material.module';
|
||||||
|
import { ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { ApplicationComponent } from '../application/application.component';
|
||||||
|
import { StepperSelectionEvent } from '@angular/cdk/stepper';
|
||||||
|
import { GoodsComponent } from '../goods/goods.component';
|
||||||
|
import { HolderComponent } from '../holder/holder.component';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { DeliveryComponent } from '../delivery/delivery.component';
|
||||||
|
import { InsuranceComponent } from '../insurance/insurance.component';
|
||||||
|
import { PaymentComponent } from '../payment/payment.component';
|
||||||
|
import { ShippingComponent } from '../shipping/shipping.component';
|
||||||
|
import { TravelPlanComponent } from '../travel-plan/travel-plan.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-edit-carnet',
|
selector: 'app-edit-carnet',
|
||||||
imports: [],
|
imports: [AngularMaterialModule, CommonModule, ReactiveFormsModule,
|
||||||
|
ApplicationComponent, HolderComponent, GoodsComponent, TravelPlanComponent, InsuranceComponent,
|
||||||
|
ShippingComponent, DeliveryComponent, PaymentComponent],
|
||||||
templateUrl: './edit-carnet.component.html',
|
templateUrl: './edit-carnet.component.html',
|
||||||
styleUrl: './edit-carnet.component.scss'
|
styleUrl: './edit-carnet.component.scss'
|
||||||
})
|
})
|
||||||
export class EditCarnetComponent {
|
export class EditCarnetComponent {
|
||||||
|
currentStep = 0;
|
||||||
|
isLinear = false;
|
||||||
|
applicationType: 'new' | 'additional' | 'duplicate' | 'extend' | null = 'new';
|
||||||
|
isEditMode = true; // Set to true for edit mode
|
||||||
|
headerid: number = 0;
|
||||||
|
|
||||||
|
// Track completion of each step
|
||||||
|
stepsCompleted = {
|
||||||
|
applicationDetail: true,
|
||||||
|
holderSelection: false,
|
||||||
|
goodsSection: false,
|
||||||
|
travelPlan: false,
|
||||||
|
insurance: false,
|
||||||
|
shipping: false,
|
||||||
|
deliveryMethod: false,
|
||||||
|
payment: false
|
||||||
|
};
|
||||||
|
|
||||||
|
private route = inject(ActivatedRoute);
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
const idParam = this.route.snapshot.paramMap.get('headerid');
|
||||||
|
this.headerid = idParam ? parseInt(idParam, 10) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
onStepChange(event: StepperSelectionEvent): void {
|
||||||
|
this.currentStep = event.selectedIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
onHolderSelectionSaved(completed: boolean): void {
|
||||||
|
this.stepsCompleted.holderSelection = completed;
|
||||||
|
}
|
||||||
|
|
||||||
|
onGoodsSectionSaved(completed: boolean): void {
|
||||||
|
this.stepsCompleted.goodsSection = completed;
|
||||||
|
}
|
||||||
|
|
||||||
|
onTravelPlanSaved(completed: boolean): void {
|
||||||
|
this.stepsCompleted.travelPlan = completed;
|
||||||
|
}
|
||||||
|
|
||||||
|
onInsuranceSaved(completed: boolean): void {
|
||||||
|
this.stepsCompleted.insurance = completed;
|
||||||
|
}
|
||||||
|
|
||||||
|
onShippingSaved(completed: boolean): void {
|
||||||
|
this.stepsCompleted.shipping = completed;
|
||||||
|
}
|
||||||
|
|
||||||
|
onDeliveryMethodSaved(completed: boolean): void {
|
||||||
|
this.stepsCompleted.deliveryMethod = completed;
|
||||||
|
}
|
||||||
|
|
||||||
|
onPaymentSaved(completed: boolean): void {
|
||||||
|
this.stepsCompleted.payment = completed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,6 @@ import { CommonModule } from '@angular/common';
|
|||||||
styleUrl: './goods.component.scss'
|
styleUrl: './goods.component.scss'
|
||||||
})
|
})
|
||||||
export class GoodsComponent {
|
export class GoodsComponent {
|
||||||
@Input() applicationid: number = 0;
|
@Input() headerid: number = 0;
|
||||||
@Output() completed = new EventEmitter<boolean>();
|
@Output() completed = new EventEmitter<boolean>();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import { Component, EventEmitter, Input, Output } from '@angular/core';
|
|||||||
styleUrl: './holder.component.scss'
|
styleUrl: './holder.component.scss'
|
||||||
})
|
})
|
||||||
export class HolderComponent {
|
export class HolderComponent {
|
||||||
@Input() applicationid: number = 0;
|
@Input() headerid: number = 0;
|
||||||
@Output() completed = new EventEmitter<boolean>();
|
@Output() completed = new EventEmitter<boolean>();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-insurance',
|
selector: 'app-insurance',
|
||||||
@ -7,5 +7,6 @@ import { Component } from '@angular/core';
|
|||||||
styleUrl: './insurance.component.scss'
|
styleUrl: './insurance.component.scss'
|
||||||
})
|
})
|
||||||
export class InsuranceComponent {
|
export class InsuranceComponent {
|
||||||
|
@Input() headerid: number = 0;
|
||||||
|
@Output() completed = new EventEmitter<boolean>();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-payment',
|
selector: 'app-payment',
|
||||||
@ -7,5 +7,6 @@ import { Component } from '@angular/core';
|
|||||||
styleUrl: './payment.component.scss'
|
styleUrl: './payment.component.scss'
|
||||||
})
|
})
|
||||||
export class PaymentComponent {
|
export class PaymentComponent {
|
||||||
|
@Input() headerid: number = 0;
|
||||||
|
@Output() completed = new EventEmitter<boolean>();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-shipping',
|
selector: 'app-shipping',
|
||||||
@ -7,5 +7,6 @@ import { Component } from '@angular/core';
|
|||||||
styleUrl: './shipping.component.scss'
|
styleUrl: './shipping.component.scss'
|
||||||
})
|
})
|
||||||
export class ShippingComponent {
|
export class ShippingComponent {
|
||||||
|
@Input() headerid: number = 0;
|
||||||
|
@Output() completed = new EventEmitter<boolean>();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-travel-plan',
|
selector: 'app-travel-plan',
|
||||||
@ -7,5 +7,6 @@ import { Component } from '@angular/core';
|
|||||||
styleUrl: './travel-plan.component.scss'
|
styleUrl: './travel-plan.component.scss'
|
||||||
})
|
})
|
||||||
export class TravelPlanComponent {
|
export class TravelPlanComponent {
|
||||||
|
@Input() headerid: number = 0;
|
||||||
|
@Output() completed = new EventEmitter<boolean>();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import { AuthService } from '../services/common/auth.service';
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AuthInterceptor implements HttpInterceptor {
|
export class AuthInterceptor implements HttpInterceptor {
|
||||||
|
private excludedUrls = ['/register', '/forgot-password'];
|
||||||
|
|
||||||
private isRefreshing = false;
|
private isRefreshing = false;
|
||||||
private refreshTokenSubject: BehaviorSubject<any> = new BehaviorSubject<any>(null);
|
private refreshTokenSubject: BehaviorSubject<any> = new BehaviorSubject<any>(null);
|
||||||
@ -17,7 +18,11 @@ export class AuthInterceptor implements HttpInterceptor {
|
|||||||
|
|
||||||
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||||
|
|
||||||
// Add withCredentials to all requests
|
// Add withCredentials to all requests except excluded URLs
|
||||||
|
if (this.excludedUrls.some(url => request.url.includes(url))) {
|
||||||
|
return next.handle(request);
|
||||||
|
}
|
||||||
|
|
||||||
request = request.clone({
|
request = request.clone({
|
||||||
withCredentials: true
|
withCredentials: true
|
||||||
});
|
});
|
||||||
|
|||||||
@ -13,6 +13,7 @@ export interface Menu {
|
|||||||
export interface UserDetail {
|
export interface UserDetail {
|
||||||
spid: number;
|
spid: number;
|
||||||
clientid: number;
|
clientid: number;
|
||||||
|
locationid: number;
|
||||||
urlKey: string;
|
urlKey: string;
|
||||||
logoName: string;
|
logoName: string;
|
||||||
themeName: string;
|
themeName: string;
|
||||||
|
|||||||
@ -15,29 +15,37 @@ export class ApplicationDetailService {
|
|||||||
private http = inject(HttpClient);
|
private http = inject(HttpClient);
|
||||||
private userService = inject(UserService);
|
private userService = inject(UserService);
|
||||||
|
|
||||||
getApplicationDetailsById(id: number): ApplicationDetail | any {
|
// getApplicationDetailsById(id: number): ApplicationDetail | any {
|
||||||
return this.http.get<any[]>(`${this.apiUrl}/${this.apiDb}/GetPreparerByClientid/${this.userService.getUserSpid()}/${id}`).pipe(
|
// return this.http.get<any[]>(`${this.apiUrl}/${this.apiDb}/GetPreparerByClientid/${this.userService.getUserSpid()}/${id}`).pipe(
|
||||||
filter(response => response.length > 0),
|
// filter(response => response.length > 0),
|
||||||
map(response => this.mapToApplicationDetail(response?.[0])));
|
// map(response => this.mapToApplicationDetail(response?.[0])));
|
||||||
}
|
// }
|
||||||
|
|
||||||
private mapToApplicationDetail(applicationDetails: any): ApplicationDetail {
|
// private mapToApplicationDetail(applicationDetails: any): ApplicationDetail {
|
||||||
return {
|
// return {
|
||||||
clientid: applicationDetails.CLIENTID,
|
// clientid: applicationDetails.CLIENTID,
|
||||||
spid: applicationDetails.SPID,
|
// spid: applicationDetails.SPID,
|
||||||
name: applicationDetails.P_APPLICATIONNAME,
|
// name: applicationDetails.P_APPLICATIONNAME,
|
||||||
applicationId: applicationDetails.P_HEADERID
|
// applicationId: applicationDetails.P_HEADERID
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
|
|
||||||
createApplicationDetails(data: ApplicationDetail): Observable<any> {
|
createApplicationDetails(data: ApplicationDetail): Observable<any> {
|
||||||
|
const userDetails = this.userService.getUserDetails();
|
||||||
|
|
||||||
|
if (!userDetails || !userDetails.userDetails) {
|
||||||
|
throw new Error('User details are not available');
|
||||||
|
}
|
||||||
|
|
||||||
const applicationDetails = {
|
const applicationDetails = {
|
||||||
P_SPID: this.userService.getUserSpid(),
|
P_SPID: userDetails.userDetails.spid,
|
||||||
P_CLIENTID: this.userService.getUserClientid(),
|
P_CLIENTID: userDetails.userDetails.clientid,
|
||||||
|
P_LOCATIONID: userDetails.userDetails.locationid,
|
||||||
P_APPLICATIONNAME: data.name,
|
P_APPLICATIONNAME: data.name,
|
||||||
|
P_ORDERTYPE: 'ORIGINAL',
|
||||||
P_USERID: this.userService.getUser(),
|
P_USERID: this.userService.getUser(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.http.post(`${this.apiUrl}/${this.apiDb}/SaveCarnetApplication`, applicationDetails);
|
return this.http.post(`${this.apiUrl}/${this.apiDb}/CreateApplication`, applicationDetails);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||||
import { inject, Injectable } from '@angular/core';
|
import { inject, Injectable } from '@angular/core';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { environment } from '../../../../environments/environment';
|
import { environment } from '../../../../environments/environment';
|
||||||
@ -48,4 +48,25 @@ export class AuthService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
register(email: string, password: string, token: string | null): Observable<any> {
|
||||||
|
let headers = new HttpHeaders();
|
||||||
|
|
||||||
|
if (token) {
|
||||||
|
headers = headers.set('Authorization', `Bearer ${token}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.http.post(
|
||||||
|
`${this.apiUrl}/register`,
|
||||||
|
{ P_EMAILADDR: email, P_PASSWORD: password },
|
||||||
|
{ headers }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
forgotPassword(email: string, password: string): Observable<any> {
|
||||||
|
return this.http.post(
|
||||||
|
`${this.apiUrl}/forgot-password`,
|
||||||
|
{ P_EMAILADDR: email, P_PASSWORD: password }
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,9 +12,6 @@ export class UserService {
|
|||||||
private apiUrl = environment.apiUrl;
|
private apiUrl = environment.apiUrl;
|
||||||
private apiDb = environment.apiDb;
|
private apiDb = environment.apiDb;
|
||||||
|
|
||||||
private spid: number = 0;
|
|
||||||
private clientid: number = 0;
|
|
||||||
|
|
||||||
userDetailsSignal = signal<User>({});
|
userDetailsSignal = signal<User>({});
|
||||||
|
|
||||||
private readonly USER_EMAIL_KEY = 'CurrentUserEmail';
|
private readonly USER_EMAIL_KEY = 'CurrentUserEmail';
|
||||||
@ -98,23 +95,18 @@ export class UserService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getUserSpid(): number {
|
getUserSpid(): number {
|
||||||
if (this.spid === 0) {
|
|
||||||
const userDetails = this.getUserDetails();
|
const userDetails = this.getUserDetails();
|
||||||
if (userDetails && userDetails.userDetails && userDetails.userDetails.spid) {
|
return userDetails?.userDetails?.spid ?? 0;
|
||||||
this.spid = userDetails.userDetails.spid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this.spid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getUserClientid(): number {
|
getUserClientid(): number {
|
||||||
if (this.clientid === 0) {
|
|
||||||
const userDetails = this.getUserDetails();
|
const userDetails = this.getUserDetails();
|
||||||
if (userDetails && userDetails.userDetails && userDetails.userDetails.clientid) {
|
return userDetails?.userDetails?.clientid ?? 0;
|
||||||
this.clientid = userDetails.userDetails.clientid;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return this.clientid;
|
getUserLocationid(): number {
|
||||||
|
const userDetails = this.getUserDetails();
|
||||||
|
return userDetails?.userDetails?.locationid ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private mapToUser(data: any): User {
|
private mapToUser(data: any): User {
|
||||||
@ -141,6 +133,7 @@ export class UserService {
|
|||||||
return {
|
return {
|
||||||
spid: userDetails.SPID,
|
spid: userDetails.SPID,
|
||||||
clientid: userDetails.CLIENTID,
|
clientid: userDetails.CLIENTID,
|
||||||
|
locationid: userDetails.LOCATIONID,
|
||||||
urlKey: userDetails.ENCURLKEY,
|
urlKey: userDetails.ENCURLKEY,
|
||||||
logoName: userDetails.LOGONAME,
|
logoName: userDetails.LOGONAME,
|
||||||
themeName: userDetails.THEMENAME
|
themeName: userDetails.THEMENAME
|
||||||
|
|||||||
@ -37,7 +37,8 @@ export class HomeService {
|
|||||||
issueDate: item.ISSUEDATE || null,
|
issueDate: item.ISSUEDATE || null,
|
||||||
expiryDate: item.EXPDATE || null,
|
expiryDate: item.EXPDATE || null,
|
||||||
orderType: item.ORDERTYPE,
|
orderType: item.ORDERTYPE,
|
||||||
carnetStatus: item.CARNETSTATUS
|
carnetStatus: item.CARNETSTATUS,
|
||||||
|
headerId: item.HEADERID,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
56
src/app/forgot-password/forgot-password.component.html
Normal file
56
src/app/forgot-password/forgot-password.component.html
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<div class="forgot-password-container">
|
||||||
|
<div class="forgot-password-card">
|
||||||
|
<h3 class="subtitle">Forgot Password</h3>
|
||||||
|
|
||||||
|
<form [formGroup]="forgotPasswordForm" (ngSubmit)="onSubmit()" class="forgot-password-form">
|
||||||
|
<mat-form-field appearance="outline">
|
||||||
|
<mat-label>Email</mat-label>
|
||||||
|
<input matInput formControlName="email" type="email" required>
|
||||||
|
<mat-icon matSuffix>email</mat-icon>
|
||||||
|
<mat-error *ngIf="email?.errors?.['required']">
|
||||||
|
Email is required
|
||||||
|
</mat-error>
|
||||||
|
<mat-error *ngIf="email?.errors?.['email']">
|
||||||
|
Please enter a valid email
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field appearance="outline">
|
||||||
|
<mat-label>Password</mat-label>
|
||||||
|
<input matInput formControlName="password" [type]="hidePassword ? 'password' : 'text'" required>
|
||||||
|
<button type="button" mat-icon-button matSuffix (click)="hidePassword = !hidePassword">
|
||||||
|
<mat-icon>{{ hidePassword ? 'visibility_off' : 'visibility' }}</mat-icon>
|
||||||
|
</button>
|
||||||
|
<mat-error *ngIf="password?.errors?.['required']">
|
||||||
|
Password is required
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<div class="login">
|
||||||
|
<a href="#" routerLink="/login" class="login-link">Already have an account? Login</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button mat-raised-button color="primary" type="submit"
|
||||||
|
[disabled]="forgotPasswordForm.invalid || isLoading">
|
||||||
|
<span *ngIf="!isLoading">Submit</span>
|
||||||
|
<mat-spinner *ngIf="isLoading" diameter="20"></mat-spinner>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="info-section">
|
||||||
|
<h3>ATA Carnet</h3>
|
||||||
|
<p>
|
||||||
|
Also known as the "Merchandise Passport," is an international customs document that simplifies temporary
|
||||||
|
exports to over 79 countries and territories.
|
||||||
|
It allows businesses to explore new markets, showcase products at trade shows, and attend global conferences
|
||||||
|
without paying duties or taxes.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
It simplifies customs procedures for the temporary movement of goods and allows goods to
|
||||||
|
enter Customs territories of the ATA Carnet system free of customs duties and taxes for up to
|
||||||
|
one year.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
95
src/app/forgot-password/forgot-password.component.scss
Normal file
95
src/app/forgot-password/forgot-password.component.scss
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
/* forgot-password.component.scss */
|
||||||
|
.forgot-password-container {
|
||||||
|
display: flex;
|
||||||
|
min-height: 85vh;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
|
||||||
|
.forgot-password-card {
|
||||||
|
flex: 1;
|
||||||
|
max-width: 500px;
|
||||||
|
padding: 2rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: white;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
text-align: center;
|
||||||
|
color: #666;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.forgot-password-form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1.5rem;
|
||||||
|
|
||||||
|
mat-form-field {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login {
|
||||||
|
text-align: right;
|
||||||
|
margin-top: -1rem;
|
||||||
|
|
||||||
|
.login-link {
|
||||||
|
color: #666;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mdc-icon-button {
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// button {
|
||||||
|
// margin-top: 1rem;
|
||||||
|
// padding: 0.5rem;
|
||||||
|
// font-size: 1rem;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-section {
|
||||||
|
flex: 1;
|
||||||
|
padding: 4rem;
|
||||||
|
background-color: #597b7c;
|
||||||
|
color: white;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 2rem;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
line-height: 1.6;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.forgot-password-container {
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.forgot-password-card {
|
||||||
|
max-width: 100%;
|
||||||
|
padding: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-section {
|
||||||
|
padding: 2rem;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
71
src/app/forgot-password/forgot-password.component.ts
Normal file
71
src/app/forgot-password/forgot-password.component.ts
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import { Component, inject } from '@angular/core';
|
||||||
|
import { FormGroup, FormBuilder, Validators, ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { ApiErrorHandlerService } from '../core/services/common/api-error-handler.service';
|
||||||
|
import { AuthService } from '../core/services/common/auth.service';
|
||||||
|
import { NotificationService } from '../core/services/common/notification.service';
|
||||||
|
import { ThemeService } from '../core/services/theme.service';
|
||||||
|
import { AngularMaterialModule } from '../shared/module/angular-material.module';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-forgot-password',
|
||||||
|
imports: [AngularMaterialModule, ReactiveFormsModule, CommonModule],
|
||||||
|
templateUrl: './forgot-password.component.html',
|
||||||
|
styleUrl: './forgot-password.component.scss'
|
||||||
|
})
|
||||||
|
export class ForgotPasswordComponent {
|
||||||
|
|
||||||
|
forgotPasswordForm: FormGroup;
|
||||||
|
isLoading = false;
|
||||||
|
hidePassword = true;
|
||||||
|
|
||||||
|
private fb = inject(FormBuilder);
|
||||||
|
private authService = inject(AuthService);
|
||||||
|
private router = inject(Router);
|
||||||
|
private notificationService = inject(NotificationService);
|
||||||
|
private errorHandler = inject(ApiErrorHandlerService);
|
||||||
|
private themeService = inject(ThemeService);
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.forgotPasswordForm = this.fb.group({
|
||||||
|
email: ['', [Validators.required, Validators.email]],
|
||||||
|
password: ['', [Validators.required]]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.themeService.setTheme('default');
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit(): void {
|
||||||
|
if (this.forgotPasswordForm.invalid) {
|
||||||
|
this.forgotPasswordForm.markAllAsTouched();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isLoading = true;
|
||||||
|
const { email, password } = this.forgotPasswordForm.value;
|
||||||
|
|
||||||
|
this.authService.forgotPassword(email, password).subscribe({
|
||||||
|
next: () => {
|
||||||
|
this.notificationService.showSuccess('Request successful');
|
||||||
|
this.router.navigate(['/login']);
|
||||||
|
},
|
||||||
|
error: (error) => {
|
||||||
|
this.isLoading = false;
|
||||||
|
let errorMessage = this.errorHandler.handleApiError(error, `Request failed. Please try again.`);
|
||||||
|
this.notificationService.showError(errorMessage);
|
||||||
|
console.error('Forgot password request failed:', error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get email() {
|
||||||
|
return this.forgotPasswordForm.get('email');
|
||||||
|
}
|
||||||
|
|
||||||
|
get password() {
|
||||||
|
return this.forgotPasswordForm.get('password');
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,6 +5,7 @@ import { BaseChartDirective } from 'ng2-charts';
|
|||||||
import { AngularMaterialModule } from '../../shared/module/angular-material.module';
|
import { AngularMaterialModule } from '../../shared/module/angular-material.module';
|
||||||
import { CarnetStatus } from '../../core/models/carnet-status';
|
import { CarnetStatus } from '../../core/models/carnet-status';
|
||||||
import { NavigationService } from '../../core/services/common/navigation.service';
|
import { NavigationService } from '../../core/services/common/navigation.service';
|
||||||
|
import { UserService } from '../../core/services/common/user.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-chart',
|
selector: 'app-chart',
|
||||||
@ -18,6 +19,7 @@ export class ChartComponent {
|
|||||||
@Output() carnetStatusData = new EventEmitter<any>();
|
@Output() carnetStatusData = new EventEmitter<any>();
|
||||||
|
|
||||||
private navigationService = inject(NavigationService);
|
private navigationService = inject(NavigationService);
|
||||||
|
private userService = inject(UserService);
|
||||||
|
|
||||||
navigateToManageProvider(spid: number): void {
|
navigateToManageProvider(spid: number): void {
|
||||||
this.navigationService.navigate(['service-provider', spid]);
|
this.navigationService.navigate(['service-provider', spid]);
|
||||||
@ -98,8 +100,8 @@ export class ChartComponent {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: provider.Service_Provider_Name,
|
title: provider.Service_Provider_Name ?? provider.Preparer_Name,
|
||||||
spid: provider.SPID,
|
spid: provider.SPID ?? this.userService.getUserSpid(),
|
||||||
data: {
|
data: {
|
||||||
labels: labels,
|
labels: labels,
|
||||||
datasets: [{
|
datasets: [{
|
||||||
|
|||||||
@ -1,17 +1,48 @@
|
|||||||
<div class="dashboard-container">
|
<div class="dashboard-container">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="quick-actions">
|
<div class="app-container">
|
||||||
<button mat-raised-button (click)="navigateTo('add-carnet')" color="accent">
|
|
||||||
<mat-icon>add</mat-icon> Add New Carnet
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Chart Section -->
|
<!-- Chart Section -->
|
||||||
<div class="chart-section">
|
<div class="chart-section">
|
||||||
<app-chart [chartData]="carnetData" [carnetStatuses]="carnetStatuses"
|
<app-chart [chartData]="carnetData" [carnetStatuses]="carnetStatuses"
|
||||||
(carnetStatusData)="onCarnetStatusClick($event)"></app-chart>
|
(carnetStatusData)="onCarnetStatusClick($event)"></app-chart>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Questions Section -->
|
||||||
|
<div class="questions-section">
|
||||||
|
<div class="question-row">
|
||||||
|
<mat-radio-group (change)="newCarnet($event)">
|
||||||
|
<mat-label>Do you need a new carnet?</mat-label>
|
||||||
|
<mat-radio-button [value]="true">Yes</mat-radio-button>
|
||||||
|
<mat-radio-button [value]="false">No</mat-radio-button>
|
||||||
|
</mat-radio-group>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="question-row">
|
||||||
|
<mat-radio-group (change)="additionalSets($event)">
|
||||||
|
<mat-label>Do you need additional sets?</mat-label>
|
||||||
|
<mat-radio-button [value]="true">Yes</mat-radio-button>
|
||||||
|
<mat-radio-button [value]="false">No</mat-radio-button>
|
||||||
|
</mat-radio-group>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="question-row">
|
||||||
|
<mat-radio-group (change)="duplicateCarnet($event)">
|
||||||
|
<mat-label>Did you lose your carnet? Are you looking for duplicates?</mat-label>
|
||||||
|
<mat-radio-button [value]="true">Yes</mat-radio-button>
|
||||||
|
<mat-radio-button [value]="false">No</mat-radio-button>
|
||||||
|
</mat-radio-group>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="question-row">
|
||||||
|
<mat-radio-group (change)="extendCarnet($event)">
|
||||||
|
<mat-label>Do you need to extend the carnet?</mat-label>
|
||||||
|
<mat-radio-button [value]="true">Yes</mat-radio-button>
|
||||||
|
<mat-radio-button [value]="false">No</mat-radio-button>
|
||||||
|
</mat-radio-group>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Carnet Details Section -->
|
<!-- Carnet Details Section -->
|
||||||
<div class="carnet-details-section">
|
<div class="carnet-details-section">
|
||||||
<div class="loading-shade" *ngIf="isLoading">
|
<div class="loading-shade" *ngIf="isLoading">
|
||||||
@ -79,7 +110,7 @@
|
|||||||
<ng-container matColumnDef="actions">
|
<ng-container matColumnDef="actions">
|
||||||
<th mat-header-cell *matHeaderCellDef>Actions</th>
|
<th mat-header-cell *matHeaderCellDef>Actions</th>
|
||||||
<td mat-cell *matCellDef="let item">
|
<td mat-cell *matCellDef="let item">
|
||||||
<button mat-icon-button color="primary"
|
<button mat-icon-button color="primary" (click)="editCarnet(item)"
|
||||||
*ngIf="getCarnetStatusLabel(item.carnetStatus) === 'Pending'"
|
*ngIf="getCarnetStatusLabel(item.carnetStatus) === 'Pending'"
|
||||||
[hidden]="getCarnetStatusLabel(item.carnetStatus) === 'Pending'" matTooltip="Edit">
|
[hidden]="getCarnetStatusLabel(item.carnetStatus) === 'Pending'" matTooltip="Edit">
|
||||||
<mat-icon>edit</mat-icon>
|
<mat-icon>edit</mat-icon>
|
||||||
|
|||||||
@ -1,12 +1,42 @@
|
|||||||
.dashboard-container {
|
.dashboard-container {
|
||||||
padding: 24px;
|
// padding: 24px;
|
||||||
|
|
||||||
.quick-actions {
|
// .quick-actions {
|
||||||
|
// display: flex;
|
||||||
|
// justify-content: end;
|
||||||
|
|
||||||
|
// button {
|
||||||
|
// margin-bottom: 16px;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
.app-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: end;
|
gap: 16px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
button {
|
.chart-section {
|
||||||
margin-bottom: 16px;
|
flex: 0 0 30%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.questions-section {
|
||||||
|
flex: 0 0 70%;
|
||||||
|
padding: 24px 0px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
margin-left: 1rem;
|
||||||
|
|
||||||
|
.question-row {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
|
||||||
|
mat-radio-group {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
mat-radio-button {
|
||||||
|
margin-top: -5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import { ApiErrorHandlerService } from '../core/services/common/api-error-handle
|
|||||||
import { CommonService } from '../core/services/common/common.service';
|
import { CommonService } from '../core/services/common/common.service';
|
||||||
import { NotificationService } from '../core/services/common/notification.service';
|
import { NotificationService } from '../core/services/common/notification.service';
|
||||||
import { NavigationService } from '../core/services/common/navigation.service';
|
import { NavigationService } from '../core/services/common/navigation.service';
|
||||||
|
import { MatRadioChange } from '@angular/material/radio';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-home',
|
selector: 'app-home',
|
||||||
@ -111,6 +112,29 @@ export class HomeComponent {
|
|||||||
return carnetStatus ? carnetStatus.name : value;
|
return carnetStatus ? carnetStatus.name : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
newCarnet(event: MatRadioChange): void {
|
||||||
|
if (event.value) {
|
||||||
|
this.navigateTo('add-carnet');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
additionalSets(event: MatRadioChange): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
duplicateCarnet(event: MatRadioChange): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
extendCarnet(event: MatRadioChange): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
editCarnet(item: any): void {
|
||||||
|
if (item && item.headerId) {
|
||||||
|
this.navigateTo(`edit-carnet/${item.headerId}?ApplicationName=${item.applicationName}`);
|
||||||
|
} else {
|
||||||
|
this.notificationService.showError('Invalid carnet data');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
navigateTo(route: string): void {
|
navigateTo(route: string): void {
|
||||||
this.navigationService.navigate([route]);
|
this.navigationService.navigate([route]);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,7 +22,7 @@
|
|||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<div class="forgot-password">
|
<div class="forgot-password">
|
||||||
<a href="#" class="forgot-link">Forgot your password?</a>
|
<a href="#" routerLink="/forgot-password" class="forgot-link">Forgot your password?</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button mat-raised-button color="primary" type="submit" [disabled]="!loginForm.valid">
|
<button mat-raised-button color="primary" type="submit" [disabled]="!loginForm.valid">
|
||||||
|
|||||||
@ -7,10 +7,11 @@ import { NavigationService } from '../core/services/common/navigation.service';
|
|||||||
import { UserService } from '../core/services/common/user.service';
|
import { UserService } from '../core/services/common/user.service';
|
||||||
import { User } from '../core/models/user';
|
import { User } from '../core/models/user';
|
||||||
import { ThemeService } from '../core/services/theme.service';
|
import { ThemeService } from '../core/services/theme.service';
|
||||||
|
import { RouterModule } from '@angular/router';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-login',
|
selector: 'app-login',
|
||||||
imports: [ReactiveFormsModule, CommonModule, AngularMaterialModule],
|
imports: [ReactiveFormsModule, CommonModule, AngularMaterialModule, RouterModule],
|
||||||
templateUrl: './login.component.html',
|
templateUrl: './login.component.html',
|
||||||
styleUrl: './login.component.scss'
|
styleUrl: './login.component.scss'
|
||||||
})
|
})
|
||||||
|
|||||||
64
src/app/register/register.component.html
Normal file
64
src/app/register/register.component.html
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
<div class="registration-container">
|
||||||
|
<div class="registration-card">
|
||||||
|
<h3 class="subtitle">User Registration</h3>
|
||||||
|
|
||||||
|
<!-- Show error message if token is invalid -->
|
||||||
|
<div *ngIf="tokenError" class="token-error">
|
||||||
|
<mat-error>
|
||||||
|
<mat-icon>error_outline</mat-icon>
|
||||||
|
<span>Invalid registration link. Please request a new registration link from your
|
||||||
|
administrator.</span>
|
||||||
|
</mat-error>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form *ngIf="!tokenError" [formGroup]="registrationForm" (ngSubmit)="onSubmit()" class="registration-form">
|
||||||
|
<mat-form-field appearance="outline">
|
||||||
|
<mat-label>Email</mat-label>
|
||||||
|
<input matInput formControlName="email" type="email" required>
|
||||||
|
<mat-icon matSuffix>email</mat-icon>
|
||||||
|
<mat-error *ngIf="email?.errors?.['required']">
|
||||||
|
Email is required
|
||||||
|
</mat-error>
|
||||||
|
<mat-error *ngIf="email?.errors?.['email']">
|
||||||
|
Please enter a valid email
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field appearance="outline">
|
||||||
|
<mat-label>Password</mat-label>
|
||||||
|
<input matInput formControlName="password" [type]="hidePassword ? 'password' : 'text'" required>
|
||||||
|
<button type="button" mat-icon-button matSuffix (click)="hidePassword = !hidePassword">
|
||||||
|
<mat-icon>{{ hidePassword ? 'visibility_off' : 'visibility' }}</mat-icon>
|
||||||
|
</button>
|
||||||
|
<mat-error *ngIf="password?.errors?.['required']">
|
||||||
|
Password is required
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<div class="login">
|
||||||
|
<a href="#" routerLink="/login" class="login-link">Already have an account? Login</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button mat-raised-button color="primary" type="submit" [disabled]="registrationForm.invalid || isLoading">
|
||||||
|
<span *ngIf="!isLoading">Register</span>
|
||||||
|
<mat-spinner *ngIf="isLoading" diameter="20"></mat-spinner>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="info-section">
|
||||||
|
<h3>ATA Carnet</h3>
|
||||||
|
<p>
|
||||||
|
Also known as the "Merchandise Passport," is an international customs document that simplifies temporary
|
||||||
|
exports to over 79 countries and territories.
|
||||||
|
It allows businesses to explore new markets, showcase products at trade shows, and attend global conferences
|
||||||
|
without paying duties or taxes.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
It simplifies customs procedures for the temporary movement of goods and allows goods to
|
||||||
|
enter Customs territories of the ATA Carnet system free of customs duties and taxes for up to
|
||||||
|
one year.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
95
src/app/register/register.component.scss
Normal file
95
src/app/register/register.component.scss
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
/* registration.component.scss */
|
||||||
|
.registration-container {
|
||||||
|
display: flex;
|
||||||
|
min-height: 85vh;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
|
||||||
|
.registration-card {
|
||||||
|
flex: 1;
|
||||||
|
max-width: 500px;
|
||||||
|
padding: 2rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: white;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
text-align: center;
|
||||||
|
color: #666;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.registration-form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1.5rem;
|
||||||
|
|
||||||
|
mat-form-field {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login {
|
||||||
|
text-align: right;
|
||||||
|
margin-top: -1rem;
|
||||||
|
|
||||||
|
.login-link {
|
||||||
|
color: #666;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mdc-icon-button {
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// button {
|
||||||
|
// margin-top: 1rem;
|
||||||
|
// padding: 0.5rem;
|
||||||
|
// font-size: 1rem;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-section {
|
||||||
|
flex: 1;
|
||||||
|
padding: 4rem;
|
||||||
|
background-color: #597b7c;
|
||||||
|
color: white;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 2rem;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
line-height: 1.6;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.registration-container {
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.registration-card {
|
||||||
|
max-width: 100%;
|
||||||
|
padding: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-section {
|
||||||
|
padding: 2rem;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
82
src/app/register/register.component.ts
Normal file
82
src/app/register/register.component.ts
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
import { Component, inject } from '@angular/core';
|
||||||
|
import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { AuthService } from '../core/services/common/auth.service';
|
||||||
|
import { NotificationService } from '../core/services/common/notification.service';
|
||||||
|
import { AngularMaterialModule } from '../shared/module/angular-material.module';
|
||||||
|
import { ApiErrorHandlerService } from '../core/services/common/api-error-handler.service';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { ThemeService } from '../core/services/theme.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-register',
|
||||||
|
imports: [AngularMaterialModule, ReactiveFormsModule, CommonModule],
|
||||||
|
templateUrl: './register.component.html',
|
||||||
|
styleUrl: './register.component.scss'
|
||||||
|
})
|
||||||
|
export class RegisterComponent {
|
||||||
|
|
||||||
|
registrationForm: FormGroup;
|
||||||
|
isLoading = false;
|
||||||
|
hidePassword = true;
|
||||||
|
tokenError: boolean = false;
|
||||||
|
token: string | null = null;
|
||||||
|
|
||||||
|
private fb = inject(FormBuilder);
|
||||||
|
private authService = inject(AuthService);
|
||||||
|
private router = inject(Router);
|
||||||
|
private route = inject(ActivatedRoute);
|
||||||
|
private notificationService = inject(NotificationService);
|
||||||
|
private errorHandler = inject(ApiErrorHandlerService);
|
||||||
|
private themeService = inject(ThemeService);
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.registrationForm = this.fb.group({
|
||||||
|
email: ['', [Validators.required, Validators.email]],
|
||||||
|
password: ['', [Validators.required]]
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get token from URL if present
|
||||||
|
this.token = this.route.snapshot.paramMap.get('token');
|
||||||
|
|
||||||
|
// Check if token is null or empty
|
||||||
|
if (!this.token || this.token.trim() === '') {
|
||||||
|
this.tokenError = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.themeService.setTheme('default');
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit(): void {
|
||||||
|
if (this.registrationForm.invalid) {
|
||||||
|
this.registrationForm.markAllAsTouched();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isLoading = true;
|
||||||
|
const { email, password } = this.registrationForm.value;
|
||||||
|
|
||||||
|
this.authService.register(email, password, this.token).subscribe({
|
||||||
|
next: () => {
|
||||||
|
this.notificationService.showSuccess('Registration successful');
|
||||||
|
this.router.navigate(['/login']);
|
||||||
|
},
|
||||||
|
error: (error) => {
|
||||||
|
this.isLoading = false;
|
||||||
|
let errorMessage = `Registration failed. Please request a new registration link from your administrator.`;
|
||||||
|
this.notificationService.showError(errorMessage);
|
||||||
|
console.error('Registration failed:', error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get email() {
|
||||||
|
return this.registrationForm.get('email');
|
||||||
|
}
|
||||||
|
|
||||||
|
get password() {
|
||||||
|
return this.registrationForm.get('password');
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user