From 00f118d0d917b35b31840fe1bdc1f59d788a7fc5 Mon Sep 17 00:00:00 2001 From: aastha Date: Fri, 27 Dec 2024 02:19:39 +0530 Subject: [PATCH 1/7] Minor --- ...nder-onboarding-opt-in-step.component.html | 112 +++++ ...nder-onboarding-opt-in-step.component.scss | 432 ++++++++++++++++++ ...r-onboarding-opt-in-step.component.spec.ts | 0 ...pender-onboarding-opt-in-step.component.ts | 319 +++++++++++++ .../spender-onboarding.module.ts | 3 +- .../spender-onboarding.page.html | 8 +- 6 files changed, 872 insertions(+), 2 deletions(-) create mode 100644 src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.html create mode 100644 src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.scss create mode 100644 src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.spec.ts create mode 100644 src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.ts diff --git a/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.html b/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.html new file mode 100644 index 0000000000..6019980220 --- /dev/null +++ b/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.html @@ -0,0 +1,112 @@ +
+
+
Opt in to send text receipts
+
This will help you send receipts via text message.
+
+ + + +
+ +
+
+ Mobile Number + * +
+ + {{ + mobileNumberError + }} +
+
+ +
+ Enter 6 digit code sent to your phone {{ mobileNumberInputValue }} + + + +
+
+ +
+ + + Resend code in + + 0:{{ otpTimer | number : '2.0' }} + + ({{ otpAttemptsLeft }} attempts left) + + + + + + ({{ otpAttemptsLeft }} attempts left) + +
+ Resend Code + (0 attempts left) +
+
+
+
+
+ +
+ +
You are all set
+
+ We have sent you a confirmation message. You can now use text messages to create and submit your next expense! +
+
+
+
+ +
+ + + Go back + + + Continue + +
+
diff --git a/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.scss b/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.scss new file mode 100644 index 0000000000..6ea9893ca6 --- /dev/null +++ b/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.scss @@ -0,0 +1,432 @@ +@import '../../../../theme/colors.scss'; + +.opt-in-step { + position: relative; + height: 100%; + + &__body { + display: flex; + flex-direction: column; + justify-content: space-between; + height: 100%; + } + + &__primary-cta-container { + display: flex; + flex-direction: row; + justify-content: flex-end; + } + + &__card-number-input { + width: fit-content !important; + margin-right: 24px; + &::placeholder { + word-spacing: 24px; + } + } + + &__heading { + color: $black; + font-size: 20px; + font-weight: 500; + line-height: normal; + margin-bottom: 8px; + margin-top: 32px; + } + + &__sub-heading { + color: $dark-grey; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 1.28; + margin-bottom: 32px; + } + + &__primary-cta { + width: 108px; + align-self: flex-end; + } + + &__toolbar-title { + font-size: 20px; + font-weight: 500; + color: $black; + line-height: normal; + } + + &__toolbar-close-btn { + position: absolute; + } + + &__body { + display: flex; + flex-direction: column; + } + + &__content { + --padding-start: 16px; + --padding-end: 16px; + --padding-top: 16px; + + max-height: 50vh; + } + + &__input-container { + padding: 16px 16px 8px 16px; + border-radius: 8px; + border: 1px solid $grey; + + &:focus-within:not(&--error) { + border: 1px solid $black-light; + } + } + + &__input-label { + font-size: 12px; + color: $black-light; + margin-bottom: 6px; + } + + &__input-inner-container { + display: flex; + align-items: center; + border-bottom: 1px solid $grey; + padding-bottom: 6px; + margin-bottom: 2px; + + &--error { + border-bottom: 1px solid $red; + } + + &:focus-within:not(&--error) { + border-bottom: 1px solid $black-light; + } + } + + &__card-number-input { + border: 0; + color: $blue-black; + width: 100%; + } + + &__input-default-icon { + width: 20px; + height: 20px; + color: $grey-light; + } + + &__input-visa-icon, + &__input-mastercard-icon { + width: 38px; + height: 22px; + } + + &__input-error-space { + width: 0px; + height: 16px; + float: right; + } + + &__input-errors { + color: $red; + font-size: 12px; + line-height: 1.3; + + & > :not(:first-child) { + // Only show one error message at a time + display: none; + } + } + + &__view-tnc-btn { + width: 100%; + background: $pink-gradient; + background-clip: text; + color: transparent; + padding: 12px 0; + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + font-size: 14px; + } + + &__view-tnc-btn-icon { + width: 18px; + height: 18px; + color: $brand-primary; + } + + &__tnc { + display: flex; + flex-direction: column; + gap: 24px; + padding-top: 8px; + font-size: 14px; + } + + &__tnc-heading { + font-weight: 500; + color: $black; + } + + &__tnc-list { + margin: 0; + padding-left: 20px; + display: flex; + flex-direction: column; + gap: 16px; + } + + &__tnc-link { + color: $blue-4; + text-decoration: none; + } + + &__tnc-link-icon { + width: 16px; + height: 16px; + vertical-align: text-bottom; + } + + &__footer-toolbar { + padding: 16px; + } + + &--header, + &--content, + &--footer { + --ion-background-color: #{$grey-9}; + background: #{$grey-9}; + } + + &--toolbar { + margin-top: calc(env(safe-area-inset-top)); + border: 0; + } + + &--title { + margin-right: 32px; + + &__icon { + width: 70px; + height: 24px; + } + } + + &--try-ai-text { + margin-left: 6px; + font-weight: 500; + } + + &--description { + font-size: 20px; + font-weight: 500; + margin-bottom: 48px; + line-height: 1.5; + } + + &--sparkle-icon { + width: 21px; + height: 21px; + } + + &--container { + margin-top: 10vh; + padding: 16px 16px 36px; + } + + &--edit-icon { + color: $brand-primary; + margin-left: 4px; + margin-bottom: -2px; + } + + &--mobile-input-container { + &__label { + margin-right: 8px; + color: $black-light; + line-height: 1.3; + font-weight: 400; + font-size: 12px; + } + + &__mandatory { + color: $red; + } + + &__input::placeholder { + font-size: 12px; + font-weight: 400; + } + + &__input { + border: 0; + border-radius: 0; + font-weight: 600; + line-height: 1.3; + color: $blue-black; + width: 100%; + padding: 6px 0; + border-bottom: 1px solid $grey-lighter; + font-size: 20px; + + &__error { + border-bottom: 1px solid $red; + } + } + + &__input:focus { + border-bottom: 1px solid $blue-black; + } + + &__error { + color: $red; + font-size: 12px; + } + } + + &--primary-cta { + margin: 16px auto; + width: 90%; + + .mat-button-base { + width: 100%; + font-weight: 700; + min-height: 47px; + } + } + + &--otp-container { + display: flex; + justify-content: center; + align-items: center; + margin-bottom: 32px; + + &__label { + margin: 0 8px 0 0; + color: $black-light; + line-height: 1.3; + font-weight: 400; + display: flex; + justify-content: space-between; + align-items: center; + + &__attempts { + font-size: 12px; + margin-left: 8px; + } + + &__resend { + color: $brand-primary; + font-size: 14px; + font-weight: 500; + background: none; + + &--disabled { + @extend .opt-in-step--otp-container__label__resend; + opacity: 0.6; + } + } + + &__otp-timer { + font-size: 14px; + + &--timer { + color: $brand-primary; + } + } + } + + &__mandatory { + color: $red; + } + + &__input { + border: 0; + border-radius: 0; + font-weight: 400; + line-height: 1.3; + color: $blue-black; + width: 100%; + padding: 8px 0; + border-bottom: 1px solid $grey-lighter; + + &--error { + border-bottom: 1px solid $red; + } + } + + &__input:focus { + border-bottom: 1px solid $blue-black; + } + + &__error { + color: $red; + font-size: 12px; + } + + &__info-box { + margin-bottom: 24px; + } + } + + &--send-code-btn { + background: linear-gradient(162.38deg, #ff3366 3.01%, #fe5196 111.5%); + &__icon { + width: 12px; + height: 14px; + margin-left: 6px; + } + } + + &--success { + display: flex; + flex-direction: column; + justify-content: center; + height: 90%; + align-items: center; + margin-top: 24px; + + &__image-container { + width: 80px; + height: 80px; + margin-bottom: 24px; + color: $green; + } + + &__header { + font-weight: 600; + font-size: 24px; + } + + &__description { + margin-top: 16px; + width: 95%; + text-align: center; + padding: 0 24px; + } + + &__footer { + padding: 14px 16px; + gap: 12px; + + &--primary-cta-text, + &--secondary-cta-text { + font-weight: 500; + font-size: 14px; + } + } + + &__help-article-icon { + margin: 4px 0px 0px 6px; + width: 14px; + height: 14px; + } + } + + &--footer { + margin-bottom: calc(env(safe-area-inset-bottom)); + } +} diff --git a/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.spec.ts b/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.spec.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.ts b/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.ts new file mode 100644 index 0000000000..d6c83447a5 --- /dev/null +++ b/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.ts @@ -0,0 +1,319 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { + Component, + ElementRef, + EventEmitter, + Input, + OnChanges, + OnInit, + Output, + SimpleChanges, + ViewChild, +} from '@angular/core'; +import { + AbstractControl, + FormArray, + FormBuilder, + FormControl, + FormGroup, + ValidationErrors, + Validators, +} from '@angular/forms'; +import { MatSnackBar } from '@angular/material/snack-bar'; +import { ModalController, PopoverController } from '@ionic/angular'; +import { NgOtpInputComponent, NgOtpInputConfig } from 'ng-otp-input'; +import { catchError, concatMap, finalize, from, map, noop, of, Subscription, switchMap, tap } from 'rxjs'; +import { CardNetworkType } from 'src/app/core/enums/card-network-type'; +import { OptInFlowState } from 'src/app/core/enums/opt-in-flow-state.enum'; +import { ToastType } from 'src/app/core/enums/toast-type.enum'; +import { statementUploadedCard, visaRTFCard } from 'src/app/core/mock-data/platform-corporate-card.data'; +import { ExtendedOrgUser } from 'src/app/core/models/extended-org-user.model'; +import { OrgSettings } from 'src/app/core/models/org-settings.model'; +import { OverlayResponse } from 'src/app/core/models/overlay-response.modal'; +import { PlatformCorporateCard } from 'src/app/core/models/platform/platform-corporate-card.model'; +import { PopoverCardsList } from 'src/app/core/models/popover-cards-list.model'; +import { SnackbarProperties } from 'src/app/core/models/snackbar-properties.model'; +import { AuthService } from 'src/app/core/services/auth.service'; +import { CorporateCreditCardExpenseService } from 'src/app/core/services/corporate-credit-card-expense.service'; +import { LoaderService } from 'src/app/core/services/loader.service'; +import { MobileNumberVerificationService } from 'src/app/core/services/mobile-number-verification.service'; +import { OrgUserService } from 'src/app/core/services/org-user.service'; +import { RealTimeFeedService } from 'src/app/core/services/real-time-feed.service'; +import { SnackbarPropertiesService } from 'src/app/core/services/snackbar-properties.service'; +import { TrackingService } from 'src/app/core/services/tracking.service'; +import { UserEventService } from 'src/app/core/services/user-event.service'; +import { PopupAlertComponent } from 'src/app/shared/components/popup-alert/popup-alert.component'; +import { ToastMessageComponent } from 'src/app/shared/components/toast-message/toast-message.component'; + +@Component({ + selector: 'app-spender-onboarding-opt-in-step', + templateUrl: './spender-onboarding-opt-in-step.component.html', + styleUrls: ['./spender-onboarding-opt-in-step.component.scss'], +}) +export class SpenderOnboardingOptInStepComponent implements OnInit, OnChanges { + @ViewChild('mobileInput') mobileInputEl: ElementRef; + + @ViewChild(NgOtpInputComponent, { static: false }) ngOtpInput: NgOtpInputComponent; + + @Input() eou: ExtendedOrgUser; + + @Output() isStepComplete: EventEmitter = new EventEmitter(); + + cardForm: FormControl; + + isVisaRTFEnabled = false; + + isMastercardRTFEnabled = false; + + cardType = CardNetworkType; + + enrollableCards: PlatformCorporateCard[]; + + cardValuesMap: Record = {}; + + rtfCardType: CardNetworkType; + + cardsList: PopoverCardsList = { + successfulCards: [], + failedCards: [], + }; + + fg: FormGroup; + + optInFlowState: OptInFlowState = OptInFlowState.MOBILE_INPUT; + + mobileNumberInputValue: string; + + mobileNumberError: string; + + sendCodeLoading = false; + + otpTimer: number; + + showOtpTimer = false; + + otpError: string; + + disableResendOtp = false; + + otpAttemptsLeft: number; + + verifyingOtp = false; + + hardwareBackButtonAction: Subscription; + + otpConfig: NgOtpInputConfig = { + allowNumbersOnly: true, + length: 6, + inputStyles: { + width: '48px', + height: '48px', + boxShadow: '0px 0px 8px 0px rgba(44, 48, 78, 0.1)', + border: 'none', + }, + }; + + constructor( + private fb: FormBuilder, + private trackingService: TrackingService, + private modalController: ModalController, + private orgUserService: OrgUserService, + private authService: AuthService, + private mobileNumberVerificationService: MobileNumberVerificationService, + private loaderService: LoaderService, + private matSnackBar: MatSnackBar, + private userEventService: UserEventService, + private snackbarProperties: SnackbarPropertiesService + ) {} + + get OptInFlowState(): typeof OptInFlowState { + return OptInFlowState; + } + + ngOnChanges(changes: SimpleChanges): void { + if (changes.eou.currentValue !== changes.eou.previousValue) { + this.mobileNumberInputValue = this.eou.ou.mobile; + } + } + + ngOnInit(): void { + this.fg = this.fb.group({}); + this.fg.addControl('mobile_number', this.fb.control('', [Validators.required, Validators.maxLength(10)])); + } + + goBack(): void { + if (this.optInFlowState === OptInFlowState.OTP_VERIFICATION) { + this.trackingService.optInFlowRetry({ + message: 'EDIT_NUMBER', + }); + this.optInFlowState = OptInFlowState.MOBILE_INPUT; + } else if (this.optInFlowState === OptInFlowState.SUCCESS) { + this.trackingService.optInFlowSuccess({ + message: 'SUCCESS', + }); + this.modalController.dismiss({ action: 'SUCCESS' }); + } else { + this.trackingService.skipOptInFlow(); + this.modalController.dismiss(); + } + } + + validateInput(): void { + if (!this.mobileNumberInputValue?.length) { + this.mobileNumberError = 'Please enter mobile number'; + } else if (!this.mobileNumberInputValue.match(/^\+1\d{10}$/)) { + this.mobileNumberError = 'Please enter a valid number with +1 country code. Try re-entering your number.'; + } + } + + saveMobileNumber(): void { + //If user has not changed the verified mobile number, close the popover + if (this.mobileNumberInputValue === this.eou.ou.mobile && this.eou.ou.mobile_verified) { + this.modalController.dismiss(); + } else { + this.validateInput(); + if (!this.mobileNumberError?.length) { + this.sendCodeLoading = true; + + const updatedOrgUserDetails = { + ...this.eou.ou, + mobile: this.mobileNumberInputValue, + }; + this.orgUserService + .postOrgUser(updatedOrgUserDetails) + .pipe(switchMap(() => this.authService.refreshEou())) + .subscribe({ + complete: () => { + this.resendOtp('INITIAL'); + }, + error: () => { + this.sendCodeLoading = false; + }, + }); + } + } + } + + resendOtp(action: 'CLICK' | 'INITIAL'): void { + this.sendCodeLoading = true; + this.mobileNumberVerificationService.sendOtp().subscribe({ + next: (otpDetails) => { + this.otpAttemptsLeft = otpDetails.attempts_left; + + if (action === 'INITIAL') { + this.optInFlowState = OptInFlowState.OTP_VERIFICATION; + } + + if (this.otpAttemptsLeft > 0) { + if (action === 'CLICK') { + this.toastWithoutCTA('Code sent successfully', ToastType.SUCCESS, 'msb-success-with-camera-icon'); + this.ngOtpInput.setValue(''); + } + this.startTimer(); + } else { + this.toastWithoutCTA( + 'You have reached the limit for 6 digit code requests. Try again after 24 hours.', + ToastType.FAILURE, + 'msb-failure-with-camera-icon' + ); + this.disableResendOtp = true; + } + + this.sendCodeLoading = false; + }, + error: (err: HttpErrorResponse) => { + if (err.status === 400) { + const error = err.error as { message: string }; + const errorMessage = error.message?.toLowerCase() || ''; + if (errorMessage.includes('out of attempts') || errorMessage.includes('max send attempts reached')) { + this.trackingService.optInFlowError({ + message: 'OTP_MAX_ATTEMPTS_REACHED', + }); + this.toastWithoutCTA( + 'You have reached the limit for 6 digit code requests. Try again after 24 hours.', + ToastType.FAILURE, + 'msb-failure-with-camera-icon' + ); + this.ngOtpInput?.setValue(''); + this.disableResendOtp = true; + } else if (errorMessage.includes('invalid parameter')) { + this.toastWithoutCTA( + 'Invalid mobile number. Please try again.', + ToastType.FAILURE, + 'msb-failure-with-camera-icon' + ); + } else if (errorMessage.includes('expired')) { + this.toastWithoutCTA( + 'The code has expired. Please request a new one.', + ToastType.FAILURE, + 'msb-failure-with-camera-icon' + ); + this.ngOtpInput?.setValue(''); + } else { + this.toastWithoutCTA('Code is invalid', ToastType.FAILURE, 'msb-failure-with-camera-icon'); + this.ngOtpInput?.setValue(''); + } + } + + this.sendCodeLoading = false; + }, + }); + } + + verifyOtp(otp: string): void { + this.verifyingOtp = true; + from(this.loaderService.showLoader('Verifying code...')) + .pipe( + switchMap(() => this.mobileNumberVerificationService.verifyOtp(otp)), + switchMap(() => this.authService.refreshEou()), + finalize(() => this.loaderService.hideLoader()) + ) + .subscribe({ + complete: () => { + this.optInFlowState = OptInFlowState.SUCCESS; + this.verifyingOtp = false; + this.userEventService.clearTaskCache(); + }, + error: () => { + this.toastWithoutCTA('Code is invalid', ToastType.FAILURE, 'msb-failure-with-camera-icon'); + this.ngOtpInput.setValue(''); + this.verifyingOtp = false; + }, + }); + } + + onOtpChange(otp: string): void { + if (otp.length === 6) { + this.verifyOtp(otp); + } + } + + toastWithoutCTA(toastMessage: string, toastType: ToastType, panelClass: string): void { + const message = toastMessage; + + this.matSnackBar.openFromComponent(ToastMessageComponent, { + ...this.snackbarProperties.setSnackbarProperties(toastType, { message }), + panelClass: [panelClass], + }); + this.trackingService.showToastMessage({ ToastContent: message }); + } + + startTimer(): void { + this.otpTimer = 30; + this.showOtpTimer = true; + const interval = setInterval(() => { + this.otpTimer--; + if (this.otpTimer === 0) { + clearInterval(interval); + this.showOtpTimer = false; + } + }, 1000); + } + + onGotItClicked(): void { + this.trackingService.optInFlowSuccess({ + message: 'SUCCESS', + }); + this.modalController.dismiss({ action: 'SUCCESS' }); + } +} diff --git a/src/app/fyle/spender-onboarding/spender-onboarding.module.ts b/src/app/fyle/spender-onboarding/spender-onboarding.module.ts index b1b3b09128..82d2d02f35 100644 --- a/src/app/fyle/spender-onboarding/spender-onboarding.module.ts +++ b/src/app/fyle/spender-onboarding/spender-onboarding.module.ts @@ -7,6 +7,7 @@ import { CommonModule } from '@angular/common'; import { SpenderOnboardingRoutingModule } from './spender-onboarding-routing.module'; import { MatButtonModule } from '@angular/material/button'; import { SpenderOnboardingConnectCardStepComponent } from './spender-onboarding-connect-card-step/spender-onboarding-connect-card-step.component'; +import { SpenderOnboardingOptInStepComponent } from './spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component'; @NgModule({ imports: [ @@ -19,6 +20,6 @@ import { SpenderOnboardingConnectCardStepComponent } from './spender-onboarding- FormsModule, ReactiveFormsModule, ], - declarations: [SpenderOnboardingPage, SpenderOnboardingConnectCardStepComponent], + declarations: [SpenderOnboardingPage, SpenderOnboardingConnectCardStepComponent, SpenderOnboardingOptInStepComponent], }) export class SpenderOnboardingPageModule {} diff --git a/src/app/fyle/spender-onboarding/spender-onboarding.page.html b/src/app/fyle/spender-onboarding/spender-onboarding.page.html index 6a79858960..6edfc287d3 100644 --- a/src/app/fyle/spender-onboarding/spender-onboarding.page.html +++ b/src/app/fyle/spender-onboarding/spender-onboarding.page.html @@ -25,11 +25,17 @@
Skip
-
+
+
+ +
From 9b06b7c0f8c18fb01f0195781a9fc23cc0fdeaa7 Mon Sep 17 00:00:00 2001 From: aastha Date: Fri, 27 Dec 2024 08:44:58 +0530 Subject: [PATCH 2/7] Minor --- ...nder-onboarding-opt-in-step.component.html | 183 ++++++++---------- ...nder-onboarding-opt-in-step.component.scss | 16 +- ...pender-onboarding-opt-in-step.component.ts | 22 +-- .../spender-onboarding.module.ts | 4 +- .../spender-onboarding.page.html | 2 +- .../spender-onboarding.page.ts | 3 + 6 files changed, 98 insertions(+), 132 deletions(-) diff --git a/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.html b/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.html index 6019980220..08d7bc29e3 100644 --- a/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.html +++ b/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.html @@ -1,111 +1,98 @@
-
Opt in to send text receipts
-
This will help you send receipts via text message.
-
+
+
Opt in to send text receipts
+
This will help you send receipts via text message.
+
- - -
- -
+
+ +
+ +
+
+ Mobile Number +
+ + {{ + mobileNumberError + }} +
+
+
Mobile Number - *
- - {{ - mobileNumberError - }} -
-
- -
- Enter 6 digit code sent to your phone {{ mobileNumberInputValue }} - - - -
-
- -
- - - Resend code in - - 0:{{ otpTimer | number : '2.0' }} +
+ {{ mobileNumberInputValue }} + + - ({{ otpAttemptsLeft }} attempts left) - - - - - - ({{ otpAttemptsLeft }} attempts left) - -
- Resend Code - (0 attempts left)
-
- -
-
- -
- -
You are all set
-
- We have sent you a confirmation message. You can now use text messages to create and submit your next expense! +
+ +
+ + + Resend code in + + 0:{{ otpTimer | number : '2.0' }} + + ({{ otpAttemptsLeft }} attempts left) + + + + + + ({{ otpAttemptsLeft }} attempts left) + +
+ Resend Code + (0 attempts left) +
+
+
-
-
- +
+ +
+ +
You are all set
+
+ We have sent you a confirmation message. You can now use text messages to create and submit your next + expense! +
+
+
+
+
-
- - - Go back - - +
+ Continue
diff --git a/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.scss b/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.scss index 6ea9893ca6..da0c93fd96 100644 --- a/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.scss +++ b/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.scss @@ -194,13 +194,6 @@ padding: 16px; } - &--header, - &--content, - &--footer { - --ion-background-color: #{$grey-9}; - background: #{$grey-9}; - } - &--toolbar { margin-top: calc(env(safe-area-inset-top)); border: 0; @@ -232,11 +225,6 @@ height: 21px; } - &--container { - margin-top: 10vh; - padding: 16px 16px 36px; - } - &--edit-icon { color: $brand-primary; margin-left: 4px; @@ -264,13 +252,13 @@ &__input { border: 0; border-radius: 0; - font-weight: 600; + font-weight: 500; line-height: 1.3; color: $blue-black; width: 100%; padding: 6px 0; border-bottom: 1px solid $grey-lighter; - font-size: 20px; + font-size: 18px; &__error { border-bottom: 1px solid $red; diff --git a/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.ts b/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.ts index d6c83447a5..28bd3e9aa1 100644 --- a/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.ts +++ b/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.ts @@ -10,39 +10,24 @@ import { SimpleChanges, ViewChild, } from '@angular/core'; -import { - AbstractControl, - FormArray, - FormBuilder, - FormControl, - FormGroup, - ValidationErrors, - Validators, -} from '@angular/forms'; +import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; import { MatSnackBar } from '@angular/material/snack-bar'; -import { ModalController, PopoverController } from '@ionic/angular'; +import { ModalController } from '@ionic/angular'; import { NgOtpInputComponent, NgOtpInputConfig } from 'ng-otp-input'; -import { catchError, concatMap, finalize, from, map, noop, of, Subscription, switchMap, tap } from 'rxjs'; +import { finalize, from, Subscription, switchMap } from 'rxjs'; import { CardNetworkType } from 'src/app/core/enums/card-network-type'; import { OptInFlowState } from 'src/app/core/enums/opt-in-flow-state.enum'; import { ToastType } from 'src/app/core/enums/toast-type.enum'; -import { statementUploadedCard, visaRTFCard } from 'src/app/core/mock-data/platform-corporate-card.data'; import { ExtendedOrgUser } from 'src/app/core/models/extended-org-user.model'; -import { OrgSettings } from 'src/app/core/models/org-settings.model'; -import { OverlayResponse } from 'src/app/core/models/overlay-response.modal'; import { PlatformCorporateCard } from 'src/app/core/models/platform/platform-corporate-card.model'; import { PopoverCardsList } from 'src/app/core/models/popover-cards-list.model'; -import { SnackbarProperties } from 'src/app/core/models/snackbar-properties.model'; import { AuthService } from 'src/app/core/services/auth.service'; -import { CorporateCreditCardExpenseService } from 'src/app/core/services/corporate-credit-card-expense.service'; import { LoaderService } from 'src/app/core/services/loader.service'; import { MobileNumberVerificationService } from 'src/app/core/services/mobile-number-verification.service'; import { OrgUserService } from 'src/app/core/services/org-user.service'; -import { RealTimeFeedService } from 'src/app/core/services/real-time-feed.service'; import { SnackbarPropertiesService } from 'src/app/core/services/snackbar-properties.service'; import { TrackingService } from 'src/app/core/services/tracking.service'; import { UserEventService } from 'src/app/core/services/user-event.service'; -import { PopupAlertComponent } from 'src/app/shared/components/popup-alert/popup-alert.component'; import { ToastMessageComponent } from 'src/app/shared/components/toast-message/toast-message.component'; @Component({ @@ -272,6 +257,7 @@ export class SpenderOnboardingOptInStepComponent implements OnInit, OnChanges { complete: () => { this.optInFlowState = OptInFlowState.SUCCESS; this.verifyingOtp = false; + this.isStepComplete.emit(true); this.userEventService.clearTaskCache(); }, error: () => { diff --git a/src/app/fyle/spender-onboarding/spender-onboarding.module.ts b/src/app/fyle/spender-onboarding/spender-onboarding.module.ts index 82d2d02f35..f5a3827051 100644 --- a/src/app/fyle/spender-onboarding/spender-onboarding.module.ts +++ b/src/app/fyle/spender-onboarding/spender-onboarding.module.ts @@ -8,17 +8,19 @@ import { SpenderOnboardingRoutingModule } from './spender-onboarding-routing.mod import { MatButtonModule } from '@angular/material/button'; import { SpenderOnboardingConnectCardStepComponent } from './spender-onboarding-connect-card-step/spender-onboarding-connect-card-step.component'; import { SpenderOnboardingOptInStepComponent } from './spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component'; +import { NgOtpInputModule } from 'ng-otp-input'; @NgModule({ imports: [ - SharedModule, CommonModule, FormsModule, + SharedModule, IonicModule, MatButtonModule, SpenderOnboardingRoutingModule, FormsModule, ReactiveFormsModule, + NgOtpInputModule, ], declarations: [SpenderOnboardingPage, SpenderOnboardingConnectCardStepComponent, SpenderOnboardingOptInStepComponent], }) diff --git a/src/app/fyle/spender-onboarding/spender-onboarding.page.html b/src/app/fyle/spender-onboarding/spender-onboarding.page.html index 6edfc287d3..a6a185a2c0 100644 --- a/src/app/fyle/spender-onboarding/spender-onboarding.page.html +++ b/src/app/fyle/spender-onboarding/spender-onboarding.page.html @@ -33,7 +33,7 @@
diff --git a/src/app/fyle/spender-onboarding/spender-onboarding.page.ts b/src/app/fyle/spender-onboarding/spender-onboarding.page.ts index 236cd20f06..8ea45de5cd 100644 --- a/src/app/fyle/spender-onboarding/spender-onboarding.page.ts +++ b/src/app/fyle/spender-onboarding/spender-onboarding.page.ts @@ -23,6 +23,8 @@ export class SpenderOnboardingPage { onboardingStep: typeof OnboardingStep = OnboardingStep; + eou: ExtendedOrgUser; + constructor( private loaderService: LoaderService, private orgUserService: OrgUserService, @@ -45,6 +47,7 @@ export class SpenderOnboardingPage { ]) ), map(([eou, orgSettings, onboardingStatus, corporateCards]) => { + this.eou = eou; this.userFullName = eou.us.full_name; const isRtfEnabled = orgSettings.visa_enrollment_settings.enabled && orgSettings.mastercard_enrollment_settings.enabled; From 96823b0e0a8d1c6a7e523e5a978dd5172a62270d Mon Sep 17 00:00:00 2001 From: aastha Date: Fri, 27 Dec 2024 08:46:47 +0530 Subject: [PATCH 3/7] Minor --- src/app/fyle/spender-onboarding/spender-onboarding.page.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/fyle/spender-onboarding/spender-onboarding.page.html b/src/app/fyle/spender-onboarding/spender-onboarding.page.html index a6a185a2c0..62b6f32359 100644 --- a/src/app/fyle/spender-onboarding/spender-onboarding.page.html +++ b/src/app/fyle/spender-onboarding/spender-onboarding.page.html @@ -25,13 +25,13 @@
Skip
-
+
-
+
Date: Fri, 27 Dec 2024 08:53:35 +0530 Subject: [PATCH 4/7] Minor --- ...nder-onboarding-opt-in-step.component.html | 46 +++++++++--------- ...nder-onboarding-opt-in-step.component.scss | 48 +++++++++---------- 2 files changed, 47 insertions(+), 47 deletions(-) diff --git a/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.html b/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.html index 08d7bc29e3..1ac23d197c 100644 --- a/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.html +++ b/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.html @@ -5,58 +5,58 @@
This will help you send receipts via text message.
-
+
-
+
-
-
+
+
Mobile Number
- {{ + {{ mobileNumberError }}
-
+
Mobile Number
-
+
{{ mobileNumberInputValue }} - +
-
+
- + Resend code in - + 0:{{ otpTimer | number : '2.0' }} - ({{ otpAttemptsLeft }} attempts left) + ({{ otpAttemptsLeft }} attempts left) - ({{ otpAttemptsLeft }} attempts left) + ({{ otpAttemptsLeft }} attempts left) -
- Resend Code - (0 attempts left) +
+ Resend Code + (0 attempts left)
-
+
-
You are all set
-
+
You are all set
+
We have sent you a confirmation message. You can now use text messages to create and submit your next expense!
diff --git a/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.scss b/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.scss index da0c93fd96..fc48d3536b 100644 --- a/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.scss +++ b/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.scss @@ -65,9 +65,9 @@ } &__content { - --padding-start: 16px; - --padding-end: 16px; - --padding-top: 16px; + __padding-start: 16px; + __padding-end: 16px; + __padding-top: 16px; max-height: 50vh; } @@ -77,7 +77,7 @@ border-radius: 8px; border: 1px solid $grey; - &:focus-within:not(&--error) { + &:focus-within:not(&__error) { border: 1px solid $black-light; } } @@ -95,11 +95,11 @@ padding-bottom: 6px; margin-bottom: 2px; - &--error { + &__error { border-bottom: 1px solid $red; } - &:focus-within:not(&--error) { + &:focus-within:not(&__error) { border-bottom: 1px solid $black-light; } } @@ -194,12 +194,12 @@ padding: 16px; } - &--toolbar { + &__toolbar { margin-top: calc(env(safe-area-inset-top)); border: 0; } - &--title { + &__title { margin-right: 32px; &__icon { @@ -208,30 +208,30 @@ } } - &--try-ai-text { + &__try-ai-text { margin-left: 6px; font-weight: 500; } - &--description { + &__description { font-size: 20px; font-weight: 500; margin-bottom: 48px; line-height: 1.5; } - &--sparkle-icon { + &__sparkle-icon { width: 21px; height: 21px; } - &--edit-icon { + &__edit-icon { color: $brand-primary; margin-left: 4px; margin-bottom: -2px; } - &--mobile-input-container { + &__mobile-input-container { &__label { margin-right: 8px; color: $black-light; @@ -275,7 +275,7 @@ } } - &--primary-cta { + &__primary-cta { margin: 16px auto; width: 90%; @@ -286,7 +286,7 @@ } } - &--otp-container { + &__otp-container { display: flex; justify-content: center; align-items: center; @@ -312,8 +312,8 @@ font-weight: 500; background: none; - &--disabled { - @extend .opt-in-step--otp-container__label__resend; + &__disabled { + @extend .opt-in-step__otp-container__label__resend; opacity: 0.6; } } @@ -321,7 +321,7 @@ &__otp-timer { font-size: 14px; - &--timer { + &__timer { color: $brand-primary; } } @@ -341,7 +341,7 @@ padding: 8px 0; border-bottom: 1px solid $grey-lighter; - &--error { + &__error { border-bottom: 1px solid $red; } } @@ -360,7 +360,7 @@ } } - &--send-code-btn { + &__send-code-btn { background: linear-gradient(162.38deg, #ff3366 3.01%, #fe5196 111.5%); &__icon { width: 12px; @@ -369,7 +369,7 @@ } } - &--success { + &__success { display: flex; flex-direction: column; justify-content: center; @@ -400,8 +400,8 @@ padding: 14px 16px; gap: 12px; - &--primary-cta-text, - &--secondary-cta-text { + &__primary-cta-text, + &__secondary-cta-text { font-weight: 500; font-size: 14px; } @@ -414,7 +414,7 @@ } } - &--footer { + &__footer { margin-bottom: calc(env(safe-area-inset-bottom)); } } From 97e5243ce221f0d390817839c656f459d083a1a1 Mon Sep 17 00:00:00 2001 From: aastha Date: Thu, 2 Jan 2025 05:18:38 +0530 Subject: [PATCH 5/7] Minor --- .../spender-onboarding-opt-in-step.component.scss | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.scss b/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.scss index fc48d3536b..ecfc7b1dff 100644 --- a/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.scss +++ b/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.scss @@ -65,9 +65,9 @@ } &__content { - __padding-start: 16px; - __padding-end: 16px; - __padding-top: 16px; + --padding-start: 16px; + --padding-end: 16px; + --padding-top: 16px; max-height: 50vh; } From ba55c6f10ad0009120dd53b8ae432bd56a70534c Mon Sep 17 00:00:00 2001 From: Aastha Bist Date: Fri, 3 Jan 2025 22:54:13 +0530 Subject: [PATCH 6/7] Update spender-onboarding-opt-in-step.component.scss --- .../spender-onboarding-opt-in-step.component.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.scss b/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.scss index ecfc7b1dff..585a4626e8 100644 --- a/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.scss +++ b/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.scss @@ -73,7 +73,7 @@ } &__input-container { - padding: 16px 16px 8px 16px; + padding: 16px 16px 8px;; border-radius: 8px; border: 1px solid $grey; From 731f32eda7ebdfc7117c99bdba508718d0abba53 Mon Sep 17 00:00:00 2001 From: Aastha Bist Date: Fri, 3 Jan 2025 22:55:16 +0530 Subject: [PATCH 7/7] Update spender-onboarding-opt-in-step.component.html --- .../spender-onboarding-opt-in-step.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.html b/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.html index 1ac23d197c..b8b9bfec28 100644 --- a/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.html +++ b/src/app/fyle/spender-onboarding/spender-onboarding-opt-in-step/spender-onboarding-opt-in-step.component.html @@ -13,7 +13,7 @@
- Mobile Number + Mobile number