Skip to content

Commit 7e11fba

Browse files
authored
Merge branch 'master' into FYLE-86cxkwzq3
2 parents fa8dbee + 186ed8f commit 7e11fba

File tree

83 files changed

+4655
-334
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+4655
-334
lines changed

src/app/app.component.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Component, OnInit, EventEmitter, NgZone, ViewChild } from '@angular/core';
22
import { Platform, MenuController, NavController } from '@ionic/angular';
33
import { from, concat, Observable, noop, forkJoin } from 'rxjs';
4-
import { switchMap, shareReplay, filter, take } from 'rxjs/operators';
4+
import { switchMap, shareReplay, filter, take, map } from 'rxjs/operators';
55
import { Router, NavigationEnd, NavigationStart } from '@angular/router';
66
import { AuthService } from 'src/app/core/services/auth.service';
77
import { UserEventService } from 'src/app/core/services/user-event.service';
@@ -24,6 +24,7 @@ import { BackButtonActionPriority } from './core/models/back-button-action-prior
2424
import { BackButtonService } from './core/services/back-button.service';
2525
import { TextZoom } from '@capacitor/text-zoom';
2626
import { GmapsService } from './core/services/gmaps.service';
27+
import { SpenderOnboardingService } from './core/services/spender-onboarding.service';
2728

2829
@Component({
2930
selector: 'app-root',
@@ -68,7 +69,8 @@ export class AppComponent implements OnInit {
6869
private loginInfoService: LoginInfoService,
6970
private navController: NavController,
7071
private backButtonService: BackButtonService,
71-
private gmapsService: GmapsService
72+
private gmapsService: GmapsService,
73+
private spenderOnboardingService: SpenderOnboardingService
7274
) {
7375
this.initializeApp();
7476
this.registerBackButtonAction();
@@ -145,6 +147,22 @@ export class AppComponent implements OnInit {
145147
);
146148
}
147149

150+
setSidenavPostOnboarding(): void {
151+
this.spenderOnboardingService
152+
.setOnboardingStatusAsComplete()
153+
.pipe(
154+
switchMap(() => this.isConnected$.pipe(take(1))),
155+
map((isOnline) => {
156+
if (isOnline) {
157+
this.sidemenuRef.showSideMenuOnline();
158+
} else {
159+
this.sidemenuRef.showSideMenuOffline();
160+
}
161+
})
162+
)
163+
.subscribe();
164+
}
165+
148166
ngOnInit(): void {
149167
this.setupNetworkWatcher();
150168

@@ -192,6 +210,8 @@ export class AppComponent implements OnInit {
192210
}, 500);
193211
});
194212

213+
this.setSidenavPostOnboarding();
214+
195215
this.userEventService.onLogout(() => {
196216
this.trackingService.onSignOut();
197217
this.freshChatService.destroy();

src/app/auth/new-password/new-password.page.html

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<div class="new-password__input-container">
1414
<div
1515
class="new-password__text new-password__text-block"
16-
[ngClass]="{'new-password__text__invalid': fg.controls.password.touched && !fg.controls.password.valid}"
16+
[ngClass]="{'new-password__text__password-focus': focusOnPassword && !(fg.controls.password.touched && !fg.controls.password.valid), 'new-password__text__invalid': fg.controls.password.touched && !fg.controls.password.valid}"
1717
>
1818
<div class="new-password__text-label">New password</div>
1919
<div class="new-password__password-container">
@@ -55,7 +55,7 @@
5555
<div class="new-password__input-container">
5656
<div
5757
class="new-password__text new-password__text-block"
58-
[ngClass]="{'new-password__text__invalid': fg.controls.confirmPassword.touched && !fg.controls.confirmPassword.valid}"
58+
[ngClass]="{'new-password__text__password-focus': focusOnConfirmPassword && !(fg.controls.confirmPassword.touched && !fg.controls.confirmPassword.valid), 'new-password__text__invalid': fg.controls.confirmPassword.touched && !fg.controls.confirmPassword.valid}"
5959
>
6060
<div class="new-password__text-label">Confirm new password</div>
6161
<div class="new-password__password-container">
@@ -65,6 +65,8 @@
6565
[type]="hideConfirmPassword ? 'password' : 'text'"
6666
class="new-password__text-input smartlook-show"
6767
formControlName="confirmPassword"
68+
(focus)="focusOnConfirmPassword = true"
69+
(blur)="focusOnConfirmPassword = false"
6870
/>
6971
<div
7072
class="new-password__password-icon-container"

src/app/auth/new-password/new-password.page.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@
2929
&__invalid {
3030
border-bottom: 1px solid $red;
3131
}
32+
33+
&__password-focus {
34+
border-bottom: 1px solid $black;
35+
}
3236
}
3337

3438
&__mandatory {

src/app/auth/new-password/new-password.page.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ export class NewPasswordPage implements OnInit {
4141

4242
isLoading = false;
4343

44+
focusOnPassword = false;
45+
46+
focusOnConfirmPassword = false;
47+
4448
constructor(
4549
private fb: FormBuilder,
4650
private activatedRoute: ActivatedRoute,
@@ -123,6 +127,7 @@ export class NewPasswordPage implements OnInit {
123127
}
124128

125129
setPasswordTooltip(value: boolean): void {
130+
this.focusOnPassword = value;
126131
this.showPasswordTooltip = value;
127132
}
128133

src/app/auth/sign-in/sign-in.page.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@
109109
</div>
110110
<div
111111
class="sign-in__enter-password__text sign-in__enter-password__text-block"
112-
[ngClass]="{'sign-in__enter-password__text__invalid': fg.controls.password.touched && !fg.controls.password.valid}"
112+
[ngClass]="{'sign-in__enter-password__text__password-focus': focusOnPassword && !(fg.controls.password.touched && !fg.controls.password.valid),'sign-in__enter-password__text__invalid': fg.controls.password.touched && !fg.controls.password.valid}"
113113
>
114114
<div class="sign-in__enter-password__input-container__label">Password</div>
115115
<div class="sign-in__enter-password__password-container">
@@ -119,6 +119,8 @@
119119
[type]="hidePassword ? 'password': 'text'"
120120
class="sign-in__enter-password__text-input smartlook-show"
121121
formControlName="password"
122+
(focus)="focusOnPassword = true"
123+
(blur)="focusOnPassword = false"
122124
/>
123125
<div
124126
class="sign-in__enter-password__password-icon-container"

src/app/auth/sign-in/sign-in.page.scss

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@
9494
width: 100%;
9595
padding: 6px 0;
9696
border-bottom: 1px solid $grey-lighter;
97+
-webkit-border-radius: 0px;
98+
-webkit-appearance: none;
99+
border-radius: 0;
97100
}
98101

99102
&__input:focus {
@@ -179,6 +182,10 @@
179182
&__invalid {
180183
border-bottom: 1px solid $red;
181184
}
185+
186+
&__password-focus {
187+
border-bottom: 1px solid $black;
188+
}
182189
}
183190

184191
&__password-container {

src/app/auth/sign-in/sign-in.page.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ export class SignInPage implements OnInit {
4545

4646
hardwareBackButtonAction: Subscription;
4747

48+
focusOnPassword = false;
49+
4850
constructor(
4951
private formBuilder: FormBuilder,
5052
private routerAuthService: RouterAuthService,

src/app/auth/switch-org/switch-org.page.spec.ts

Lines changed: 81 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ import { DeepLinkService } from 'src/app/core/services/deep-link.service';
4444
import { platformExpenseData } from 'src/app/core/mock-data/platform/v1/expense.data';
4545
import { transformedExpenseData } from 'src/app/core/mock-data/transformed-expense.data';
4646
import { LaunchDarklyService } from 'src/app/core/services/launch-darkly.service';
47+
import { OrgSettingsService } from 'src/app/core/services/org-settings.service';
48+
import { orgSettingsCardsDisabled, orgSettingsData } from 'src/app/core/test-data/org-settings.service.spec.data';
49+
import { SpenderOnboardingService } from 'src/app/core/services/spender-onboarding.service';
50+
import { onboardingStatusData } from 'src/app/core/mock-data/onboarding-status.data';
51+
import { OnboardingState } from 'src/app/core/models/onboarding-state.enum';
4752

4853
const roles = ['OWNER', 'USER', 'FYLER'];
4954
const email = '[email protected]';
@@ -73,6 +78,8 @@ describe('SwitchOrgPage', () => {
7378
let transactionService: jasmine.SpyObj<TransactionService>;
7479
let expensesService: jasmine.SpyObj<ExpensesService>;
7580
let deepLinkService: jasmine.SpyObj<DeepLinkService>;
81+
let orgSettingsService: jasmine.SpyObj<OrgSettingsService>;
82+
let spenderOnboardingService: jasmine.SpyObj<SpenderOnboardingService>;
7683

7784
beforeEach(waitForAsync(() => {
7885
const platformSpy = jasmine.createSpyObj('Platform', ['is']);
@@ -110,6 +117,10 @@ describe('SwitchOrgPage', () => {
110117
const expensesServiceSpy = jasmine.createSpyObj('ExpensesService', ['getExpenseById']);
111118
const deepLinkServiceSpy = jasmine.createSpyObj('DeepLinkService', ['getExpenseRoute']);
112119
const ldSpy = jasmine.createSpyObj('LaunchDarklyService', ['initializeUser']);
120+
const orgSettingsServiceSpy = jasmine.createSpyObj('OrgSettingsService', ['get']);
121+
const spenderOnboardingServiceSpy = jasmine.createSpyObj('SpenderOnboardingService', [
122+
'checkForRedirectionToOnboarding',
123+
]);
113124

114125
TestBed.configureTestingModule({
115126
declarations: [SwitchOrgPage, ActiveOrgCardComponent, OrgCardComponent, FyZeroStateComponent],
@@ -150,6 +161,14 @@ describe('SwitchOrgPage', () => {
150161
provide: LoaderService,
151162
useValue: loaderServiceSpy,
152163
},
164+
{
165+
provide: OrgSettingsService,
166+
useValue: orgSettingsServiceSpy,
167+
},
168+
{
169+
provide: SpenderOnboardingService,
170+
useValue: spenderOnboardingServiceSpy,
171+
},
153172
{
154173
provide: UserService,
155174
useValue: userServiceSpy,
@@ -256,11 +275,15 @@ describe('SwitchOrgPage', () => {
256275
deepLinkService = TestBed.inject(DeepLinkService) as jasmine.SpyObj<DeepLinkService>;
257276
transactionService = TestBed.inject(TransactionService) as jasmine.SpyObj<TransactionService>;
258277
expensesService = TestBed.inject(ExpensesService) as jasmine.SpyObj<ExpensesService>;
278+
spenderOnboardingService = TestBed.inject(SpenderOnboardingService) as jasmine.SpyObj<SpenderOnboardingService>;
279+
orgSettingsService = TestBed.inject(OrgSettingsService) as jasmine.SpyObj<OrgSettingsService>;
259280

260281
component.searchRef = fixture.debugElement.query(By.css('#search'));
261282
component.searchOrgsInput = fixture.debugElement.query(By.css('.smartlook-show'));
262283
component.contentRef = fixture.debugElement.query(By.css('.switch-org__content-container__content-block'));
263284
fixture.detectChanges();
285+
spenderOnboardingService.checkForRedirectionToOnboarding.and.returnValue(of(false));
286+
orgSettingsService.get.and.returnValue(of(orgSettingsData));
264287
}));
265288

266289
it('should create', () => {
@@ -548,6 +571,14 @@ describe('SwitchOrgPage', () => {
548571
}));
549572
});
550573

574+
it('navigateToDashboard(): should navigate to spender onboarding when onboarding status is not complete', fakeAsync(() => {
575+
spenderOnboardingService.checkForRedirectionToOnboarding.and.returnValue(of(true));
576+
orgSettingsService.get.and.returnValue(of(orgSettingsData));
577+
component.navigateToDashboard();
578+
tick();
579+
expect(router.navigate).toHaveBeenCalledOnceWith(['/', 'enterprise', 'spender_onboarding']);
580+
}));
581+
551582
describe('navigateToSetupPage():', () => {
552583
it('should navigate to setup page if org the roles has OWNER', () => {
553584
component.navigateToSetupPage(['OWNER']);
@@ -572,7 +603,12 @@ describe('SwitchOrgPage', () => {
572603
.pipe(
573604
finalize(() => {
574605
expect(loaderService.hideLoader).toHaveBeenCalledTimes(1);
575-
expect(router.navigate).toHaveBeenCalledOnceWith(['/', 'enterprise', 'my_dashboard']);
606+
expect(router.navigate).toHaveBeenCalledOnceWith([
607+
'/',
608+
'enterprise',
609+
'my_dashboard',
610+
{ openSMSOptInDialog: undefined },
611+
]);
576612
})
577613
)
578614
.subscribe((res) => {
@@ -642,16 +678,38 @@ describe('SwitchOrgPage', () => {
642678
});
643679

644680
describe('navigateBasedOnUserStatus(): ', () => {
645-
it('should navigate to dashboard if status is active', (done) => {
681+
it('should navigate to dashboard if status is active', fakeAsync(() => {
646682
const config = {
647683
isPendingDetails: false,
648684
roles,
649685
eou: apiEouRes,
650686
};
687+
orgSettingsService.get.and.returnValue(of(orgSettingsData));
688+
spenderOnboardingService.checkForRedirectionToOnboarding.and.returnValue(of(false));
689+
tick();
690+
component.navigateBasedOnUserStatus(config).subscribe((res) => {
691+
expect(res).toBeNull();
692+
expect(router.navigate).toHaveBeenCalledOnceWith([
693+
'/',
694+
'enterprise',
695+
'my_dashboard',
696+
{ openSMSOptInDialog: undefined },
697+
]);
698+
expect(spenderOnboardingService.checkForRedirectionToOnboarding).toHaveBeenCalledTimes(1);
699+
});
700+
}));
651701

702+
it('should navigate to spender onboarding if status not COMPLETE', (done) => {
703+
const config = {
704+
isPendingDetails: false,
705+
roles,
706+
eou: apiEouRes,
707+
};
708+
orgSettingsService.get.and.returnValue(of(orgSettingsData));
709+
spenderOnboardingService.checkForRedirectionToOnboarding.and.returnValue(of(true));
652710
component.navigateBasedOnUserStatus(config).subscribe((res) => {
653711
expect(res).toBeNull();
654-
expect(router.navigate).toHaveBeenCalledOnceWith(['/', 'enterprise', 'my_dashboard']);
712+
expect(router.navigate).toHaveBeenCalledOnceWith(['/', 'enterprise', 'spender_onboarding']);
655713
done();
656714
});
657715
});
@@ -670,6 +728,26 @@ describe('SwitchOrgPage', () => {
670728
});
671729
});
672730

731+
it('should navigate to dashboard when no enrollment settings are enabled', (done) => {
732+
const config = {
733+
isPendingDetails: false,
734+
roles,
735+
eou: apiEouRes,
736+
};
737+
orgSettingsService.get.and.returnValue(of(orgSettingsCardsDisabled));
738+
spenderOnboardingService.checkForRedirectionToOnboarding.and.returnValue(of(false));
739+
component.navigateBasedOnUserStatus(config).subscribe((res) => {
740+
expect(res).toBeNull();
741+
expect(router.navigate).toHaveBeenCalledWith([
742+
'/',
743+
'enterprise',
744+
'my_dashboard',
745+
{ openSMSOptInDialog: undefined },
746+
]);
747+
done();
748+
});
749+
});
750+
673751
it('should handle flow if details are pending', (done) => {
674752
spyOn(component, 'handlePendingDetails').and.returnValue(of(apiEouRes));
675753
const config = {

0 commit comments

Comments
 (0)