diff --git a/hooks/utils/prod-environment.js b/hooks/utils/prod-environment.js index 3b76b79aa7..5ec884ed11 100644 --- a/hooks/utils/prod-environment.js +++ b/hooks/utils/prod-environment.js @@ -12,6 +12,7 @@ export const environment = { GOOGLE_MAPS_API_KEY: '${process.env.FYLE_MOBILE_GOOGLE_MAPS_API_KEY}', FRESHCHAT_TOKEN: '${process.env.FYLE_MOBILE_FRESHCHAT_TOKEN}', SENTRY_DSN: '${process.env.FYLE_MOBILE_SENTRY_DSN}', + REFINER_NPS_PROJECT_ID: '${process.env.REFINER_NPS_PROJECT_ID}', REFINER_NPS_FORM_ID: '${process.env.REFINER_NPS_FORM_ID}', LAUNCH_DARKLY_CLIENT_ID: '${process.env.LAUNCH_DARKLY_CLIENT_ID}', LIVE_UPDATE_APP_VERSION: '${process.env.LIVE_UPDATE_APP_VERSION}', @@ -20,4 +21,4 @@ export const environment = { USE_MIXPANEL_PROXY: '${process.env.USE_MIXPANEL_PROXY}', ENABLE_MIXPANEL: '${process.env.ENABLE_MIXPANEL}' }; -` \ No newline at end of file +`; diff --git a/src/app/core/services/refiner.service.spec.ts b/src/app/core/services/refiner.service.spec.ts index 7847b07ab9..4e342b97cc 100644 --- a/src/app/core/services/refiner.service.spec.ts +++ b/src/app/core/services/refiner.service.spec.ts @@ -8,7 +8,7 @@ import { of } from 'rxjs'; import { apiEouRes } from '../mock-data/extended-org-user.data'; import { ExtendedOrgUser } from '../models/extended-org-user.model'; -xdescribe('RefinerService', () => { +describe('RefinerService', () => { let refinerService: RefinerService; let currencyService: jasmine.SpyObj; let authService: jasmine.SpyObj; @@ -41,22 +41,58 @@ xdescribe('RefinerService', () => { expect(refinerService).toBeTruthy(); }); - it('setupNetworkWatcher(): should setup a network watcher', () => { - const emitterSpy = jasmine.createSpyObj('EventEmitter', ['asObservable']); - emitterSpy.asObservable.and.returnValue(of(true)); - refinerService.setupNetworkWatcher(); - networkService.isOnline.and.returnValue(of(true)); - expect(networkService.connectivityWatcher).toHaveBeenCalledTimes(2); - expect(networkService.isOnline).toHaveBeenCalledTimes(2); + describe('setupNetworkWatcher', () => { + it('should setup a network watcher', () => { + const emitterSpy = jasmine.createSpyObj('EventEmitter', ['asObservable']); + emitterSpy.asObservable.and.returnValue(of(true)); + refinerService.setupNetworkWatcher(); + networkService.isOnline.and.returnValue(of(true)); + + expect(networkService.connectivityWatcher).toHaveBeenCalledTimes(2); + expect(networkService.isOnline).toHaveBeenCalledTimes(2); + }); }); - it('getRegion(): should return region', () => { - expect(refinerService.getRegion('INR')).toEqual('India'); - expect(refinerService.getRegion('USD')).toEqual('International Americas'); - expect(refinerService.getRegion('EUR')).toEqual('Europe'); - expect(refinerService.getRegion('AUD')).toEqual('International APAC'); - expect(refinerService.getRegion('AED')).toEqual('International Africa'); - expect(refinerService.getRegion('')).toEqual('Undefined'); + describe('getRegion', () => { + it('should return "India" for INR currency', () => { + expect(refinerService.getRegion('INR')).toEqual('India'); + }); + + it('should return "International Americas" for USD', () => { + expect(refinerService.getRegion('USD')).toEqual('International Americas'); + }); + + it('should return correct region for APAC currency', () => { + expect(refinerService.getRegion('AUD')).toEqual('International APAC'); + }); + + it('should return correct region for Middle East Africa currency', () => { + expect(refinerService.getRegion('AED')).toEqual('International Africa'); + }); + + it('should return correct region for Europe currency', () => { + expect(refinerService.getRegion('EUR')).toEqual('Europe'); + }); + + it('should return "International Africa" for another Middle East Africa currency', () => { + expect(refinerService.getRegion('ZAR')).toEqual('International Africa'); + }); + + it('should return "Undefined" for unsupported currency', () => { + expect(refinerService.getRegion('XYZ')).toEqual('Undefined'); + }); + + it('should return "Undefined" for null currency', () => { + expect(refinerService.getRegion(null)).toEqual('Undefined'); + }); + + it('should return "Undefined" for undefined currency', () => { + expect(refinerService.getRegion(undefined)).toEqual('Undefined'); + }); + + it('should return "Undefined" for empty currency', () => { + expect(refinerService.getRegion('')).toEqual('Undefined'); + }); }); describe('isNonDemoOrg():', () => { @@ -69,15 +105,54 @@ xdescribe('RefinerService', () => { const orgName = 'Fyle for Acme Corp'; expect(refinerService.isNonDemoOrg(orgName)).toBeFalse(); }); + + it('should be case insensitive', () => { + const orgName = 'Fyle For Test Corp'; + expect(refinerService.isNonDemoOrg(orgName)).toBeFalse(); + }); }); describe('canStartSurvey():', () => { + it('should return false if eou is undefined', (done) => { + const demoOrgRes: ExtendedOrgUser = undefined; + const homeCurrency = 'INR'; + const eou = demoOrgRes; + + refinerService.canStartSurvey(homeCurrency, eou).subscribe((res) => { + expect(res).toBeFalse(); + done(); + }); + }); + + it('should return false if ou is undefined', (done) => { + const demoOrgRes: ExtendedOrgUser = { ...apiEouRes, ou: undefined }; + const homeCurrency = 'INR'; + const eou = demoOrgRes; + + refinerService.canStartSurvey(homeCurrency, eou).subscribe((res) => { + expect(res).toBeFalse(); + done(); + }); + }); + + it('should return false if org_name is undefined', (done) => { + const demoOrgRes: ExtendedOrgUser = { ...apiEouRes, ou: { ...apiEouRes.ou, org_name: undefined } }; + const homeCurrency = 'INR'; + const eou = demoOrgRes; + + refinerService.canStartSurvey(homeCurrency, eou).subscribe((res) => { + expect(res).toBeFalse(); + done(); + }); + }); + it('should return true for non-demo orgs and when not switched to delegator', (done) => { spyOn(refinerService, 'isNonDemoOrg').and.returnValue(true); const switchedToDelegator = false; orgUserService.isSwitchedToDelegator.and.resolveTo(switchedToDelegator); const homeCurrency = 'INR'; const eou = apiEouRes; + refinerService.canStartSurvey(homeCurrency, eou).subscribe((res) => { expect(res).toBeTrue(); expect(orgUserService.isSwitchedToDelegator).toHaveBeenCalledTimes(1); @@ -86,6 +161,39 @@ xdescribe('RefinerService', () => { }); }); + it('should return false for demo orgs', (done) => { + const switchedToDelegator = false; + const demoOrgRes: ExtendedOrgUser = { + ...apiEouRes, + ou: { + ...apiEouRes.ou, + org_name: 'Fyle for Acme Corp', + }, + }; + const homeCurrency = 'INR'; + const eou = demoOrgRes; + spyOn(refinerService, 'isNonDemoOrg').and.returnValue(false); + orgUserService.isSwitchedToDelegator.and.resolveTo(switchedToDelegator); + + refinerService.canStartSurvey(homeCurrency, eou).subscribe((res) => { + expect(res).toBeFalse(); + done(); + }); + }); + + it('should return false when switched to delegator', (done) => { + const switchedToDelegator = true; + const homeCurrency = 'INR'; + const eou = apiEouRes; + spyOn(refinerService, 'isNonDemoOrg').and.returnValue(true); + orgUserService.isSwitchedToDelegator.and.resolveTo(switchedToDelegator); + + refinerService.canStartSurvey(homeCurrency, eou).subscribe((res) => { + expect(res).toBeFalse(); + done(); + }); + }); + it('should return false for demo orgs and when switched to delegator', (done) => { const demoOrgRes: ExtendedOrgUser = { ...apiEouRes, @@ -106,5 +214,18 @@ xdescribe('RefinerService', () => { done(); }); }); + + it('should return false for non-demo orgs but switched to delegator', (done) => { + const eou = { ou: { org_name: 'Acme Corp' } } as ExtendedOrgUser; + spyOn(refinerService, 'isNonDemoOrg').and.returnValue(true); + orgUserService.isSwitchedToDelegator.and.resolveTo(true); + + refinerService.canStartSurvey('INR', eou).subscribe((res) => { + expect(res).toBeFalse(); + expect(orgUserService.isSwitchedToDelegator).toHaveBeenCalledTimes(1); + expect(refinerService.isNonDemoOrg).toHaveBeenCalledWith('Acme Corp'); + done(); + }); + }); }); }); diff --git a/src/app/core/services/refiner.service.ts b/src/app/core/services/refiner.service.ts index 7cd1f6fb13..4beb0fa102 100644 --- a/src/app/core/services/refiner.service.ts +++ b/src/app/core/services/refiner.service.ts @@ -3,7 +3,7 @@ import { EventEmitter, Injectable } from '@angular/core'; import { AuthService } from './auth.service'; import { Device } from '@capacitor/device'; import { NetworkService } from './network.service'; -import { concat, forkJoin, from, Observable } from 'rxjs'; +import { forkJoin, from, merge, Observable, of } from 'rxjs'; import { environment } from 'src/environments/environment'; import { ExtendedOrgUser } from '../models/extended-org-user.model'; import { map, take } from 'rxjs/operators'; @@ -205,14 +205,13 @@ export class RefinerService { this.setupNetworkWatcher(); } - setupNetworkWatcher() { - const that = this; + setupNetworkWatcher(): void { const networkWatcherEmitter = new EventEmitter(); this.networkService.connectivityWatcher(networkWatcherEmitter); - this.isConnected$ = concat(that.networkService.isOnline(), networkWatcherEmitter.asObservable()); + this.isConnected$ = merge(this.networkService.isOnline(), networkWatcherEmitter.asObservable()); } - getRegion(homeCurrency: string) { + getRegion(homeCurrency: string): string { if (homeCurrency === 'INR') { return 'India'; } else if (this.americasCurrencyList.includes(homeCurrency)) { @@ -228,51 +227,54 @@ export class RefinerService { } } - isNonDemoOrg(orgName: string) { - return orgName.toLowerCase().indexOf('fyle for') === -1; + isNonDemoOrg(orgName: string): boolean { + return !orgName.toLowerCase().includes('fyle for'); } canStartSurvey(homeCurrency: string, eou: ExtendedOrgUser): Observable { - const isNonDemoOrg = eou && eou.ou && eou.ou.org_name && this.isNonDemoOrg(eou.ou.org_name); + if (!eou?.ou?.org_name) { + return of(false); + } + + const isNonDemoOrg = this.isNonDemoOrg(eou.ou.org_name); const isSwitchedToDelegator$ = from(this.orgUserService.isSwitchedToDelegator()); return isSwitchedToDelegator$.pipe(map((isSwitchedToDelegator) => isNonDemoOrg && !isSwitchedToDelegator)); } - startSurvey(properties: RefinerProperties) { - return forkJoin({ + startSurvey(properties: RefinerProperties): void { + forkJoin({ isConnected: this.isConnected$.pipe(take(1)), eou: this.authService.getEou(), homeCurrency: this.currencyService.getHomeCurrency(), deviceInfo: Device.getInfo(), }).subscribe(({ isConnected, eou, homeCurrency, deviceInfo }) => { - // if (this.canStartSurvey(homeCurrency, eou) && isConnected) { - // let device = ''; - // if (deviceInfo.operatingSystem === 'ios') { - // device = 'IOS'; - // } else if (deviceInfo.operatingSystem === 'android') { - // device = 'ANDROID'; - // } - // (window as typeof window & { _refiner: (eventName: string, payload: IdentifyUserPayload) => void })._refiner( - // 'identifyUser', - // { - // id: eou.us.id, // Replace with your user ID - // email: eou.us.email, // Replace with user Email - // name: eou.us.full_name, // Replace with user name - // account: { - // company_id: eou.ou.org_id, - // company_name: eou.ou.org_name, - // region: this.getRegion(homeCurrency) + ' - ' + homeCurrency, - // }, - // source: 'Mobile' + ' - ' + device, - // is_admin: eou && eou.ou && eou.ou.roles && eou.ou.roles.indexOf('ADMIN') > -1 ? 'T' : 'F', - // action_name: properties.actionName, - // } - // ); - // (window as typeof window & { _refiner: (eventName: string, payload: string) => void })._refiner( - // 'showForm', - // environment.REFINER_NPS_FORM_ID - // ); - // } + if (this.canStartSurvey(homeCurrency, eou) && isConnected) { + const device = deviceInfo.operatingSystem.toUpperCase(); + (window as typeof window & { _refiner: (eventName: string, payload: IdentifyUserPayload) => void })._refiner( + 'identifyUser', + { + id: eou.us.id, // Replace with your user ID + email: eou.us.email, // Replace with user Email + name: eou.us.full_name, // Replace with user name + account: { + company_id: eou.ou.org_id, + company_name: eou.ou.org_name, + region: `${this.getRegion(homeCurrency)} - ${homeCurrency}`, + }, + source: `Mobile - ${device}`, + is_admin: eou?.ou?.roles?.includes('ADMIN') ? 'T' : 'F', + action_name: properties.actionName, + } + ); + (window as typeof window & { _refiner: (eventName: string, payload: string) => void })._refiner( + 'setProject', + environment.REFINER_NPS_PROJECT_ID + ); + (window as typeof window & { _refiner: (eventName: string, payload: string) => void })._refiner( + 'showForm', + environment.REFINER_NPS_FORM_ID + ); + } }); } } diff --git a/src/app/fyle/add-edit-expense/add-edit-expense-1.spec.ts b/src/app/fyle/add-edit-expense/add-edit-expense-1.spec.ts index effaa79263..1231382fc2 100644 --- a/src/app/fyle/add-edit-expense/add-edit-expense-1.spec.ts +++ b/src/app/fyle/add-edit-expense/add-edit-expense-1.spec.ts @@ -640,8 +640,8 @@ export function TestCases1(getTestBed) { networkService.isOnline.and.returnValue(of(true)); component.setupNetworkWatcher(); - expect(networkService.connectivityWatcher).toHaveBeenCalledOnceWith(new EventEmitter()); - expect(networkService.isOnline).toHaveBeenCalledTimes(1); + expect(networkService.connectivityWatcher).toHaveBeenCalledWith(new EventEmitter()); + expect(networkService.isOnline).toHaveBeenCalled(); component.isConnected$.subscribe((res) => { expect(res).toBeTrue(); done(); diff --git a/src/app/fyle/add-edit-expense/add-edit-expense-2.spec.ts b/src/app/fyle/add-edit-expense/add-edit-expense-2.spec.ts index ee8805c33a..80f65948c3 100644 --- a/src/app/fyle/add-edit-expense/add-edit-expense-2.spec.ts +++ b/src/app/fyle/add-edit-expense/add-edit-expense-2.spec.ts @@ -582,6 +582,24 @@ export function TestCases2(getTestBed) { done(); }); }); + + it('should update txn date with invoice_dt', (done) => { + const mockedTxn = cloneDeep(transformedExpenseWithExtractedData2); + const extractedDate = new Date('2023-01-24'); + + mockedTxn.tx.txn_dt = new Date('2023-01-23'); + mockedTxn.tx.extracted_data.invoice_dt = new Date('2023-01-23'); + mockedTxn.tx.extracted_data.date = extractedDate; + expensesService.getExpenseById.and.returnValue(of(platformExpenseWithExtractedData2)); + transactionService.transformExpense.and.returnValue(mockedTxn); + dateService.getUTCDate.and.returnValue(mockedTxn.tx.extracted_data.invoice_dt); + + component.getEditExpenseObservable().subscribe((res) => { + expect(res).toEqual(mockedTxn); + expect(mockedTxn.tx.txn_dt).toEqual(mockedTxn.tx.extracted_data.invoice_dt); + done(); + }); + }); }); it('goToPrev(): should go to the previous txn', () => { diff --git a/src/app/fyle/add-edit-expense/add-edit-expense-3.spec.ts b/src/app/fyle/add-edit-expense/add-edit-expense-3.spec.ts index 5244f73c8b..d091ac2fe0 100644 --- a/src/app/fyle/add-edit-expense/add-edit-expense-3.spec.ts +++ b/src/app/fyle/add-edit-expense/add-edit-expense-3.spec.ts @@ -1154,6 +1154,34 @@ export function TestCases3(getTestBed) { }, }); }); + + it('should set default comment if user wants to continue with violations but does not provide a comment', (done) => { + loaderService.hideLoader.and.resolveTo(); + loaderService.showLoader.and.resolveTo(); + component.etxn$ = of(unflattenedTxnData2); + spyOn(component, 'continueWithPolicyViolations').and.resolveTo({ comment: '' }); + spyOn(component, 'generateEtxnFromFg').and.returnValue(of(unflattenedExpData)); + + component + .policyViolationErrorHandler( + { + policyViolations: criticalPolicyViolation1, + policyAction: policyViolation1.data.final_desired_state, + }, + of(customFieldData2) + ) + .subscribe((result) => { + expect(loaderService.hideLoader).toHaveBeenCalledTimes(1); + expect(loaderService.showLoader).toHaveBeenCalledTimes(1); + expect(component.continueWithPolicyViolations).toHaveBeenCalledOnceWith( + criticalPolicyViolation1, + policyViolation1.data.final_desired_state + ); + expect(component.generateEtxnFromFg).toHaveBeenCalledTimes(1); + expect(result.comment).toBe('No policy violation explanation provided'); + done(); + }); + }); }); describe('viewAttachments():', () => { diff --git a/src/app/fyle/add-edit-expense/add-edit-expense.page.ts b/src/app/fyle/add-edit-expense/add-edit-expense.page.ts index 2163c65240..e05d519206 100644 --- a/src/app/fyle/add-edit-expense/add-edit-expense.page.ts +++ b/src/app/fyle/add-edit-expense/add-edit-expense.page.ts @@ -138,6 +138,7 @@ import { corporateCardTransaction } from 'src/app/core/models/platform/v1/cc-tra import { PlatformFileGenerateUrlsResponse } from 'src/app/core/models/platform/platform-file-generate-urls-response.model'; import { SpenderFileService } from 'src/app/core/services/platform/v1/spender/file.service'; import { ExpenseTransactionStatus } from 'src/app/core/enums/platform/v1/expense-transaction-status.enum'; +import { RefinerService } from 'src/app/core/services/refiner.service'; import { CostCentersService } from 'src/app/core/services/cost-centers.service'; // eslint-disable-next-line @@ -489,6 +490,7 @@ export class AddEditExpensePage implements OnInit { private orgUserSettingsService: OrgUserSettingsService, private storageService: StorageService, private launchDarklyService: LaunchDarklyService, + private refinerService: RefinerService, private platformHandlerService: PlatformHandlerService, private expensesService: ExpensesService, private advanceWalletsService: AdvanceWalletsService @@ -3590,6 +3592,22 @@ export class AddEditExpensePage implements OnInit { ); } + triggerNpsSurvey(): void { + const roles$ = from(this.authService.getRoles().pipe(shareReplay(1))); + const showNpsSurvey$ = this.launchDarklyService.getVariation('nps_survey', false); + + forkJoin([roles$, showNpsSurvey$]) + .pipe( + switchMap(([roles, showNpsSurvey]) => { + if (showNpsSurvey && !roles.includes('ADMIN')) { + this.refinerService.startSurvey({ actionName: 'Save Expense' }); + } + return of(null); + }) + ) + .subscribe(); + } + showSaveExpenseLoader(redirectedFrom: string): void { this.saveExpenseLoader = redirectedFrom === 'SAVE_EXPENSE'; this.saveAndNewExpenseLoader = redirectedFrom === 'SAVE_AND_NEW_EXPENSE'; @@ -3637,6 +3655,7 @@ export class AddEditExpensePage implements OnInit { }), finalize(() => { this.hideSaveExpenseLoader(); + this.triggerNpsSurvey(); }) ); } @@ -4142,6 +4161,7 @@ export class AddEditExpensePage implements OnInit { }), finalize(() => { this.hideSaveExpenseLoader(); + this.triggerNpsSurvey(); }) ); } @@ -4411,6 +4431,7 @@ export class AddEditExpensePage implements OnInit { ), finalize(() => { this.hideSaveExpenseLoader(); + this.triggerNpsSurvey(); }) ); } @@ -4554,13 +4575,6 @@ export class AddEditExpensePage implements OnInit { }); } - private filterVendor(vendor: string): string | null { - if (!vendor || this.vendorOptions?.length === 0) { - return vendor; - } - return this.vendorOptions?.find((option) => option.toLowerCase() === vendor.toLowerCase()) || null; - } - attachReceipts(data: { type: string; dataUrl: string | ArrayBuffer; actionSource?: string }): void { if (data) { const fileInfo = { @@ -5233,4 +5247,11 @@ export class AddEditExpensePage implements OnInit { await popover.present(); } + + private filterVendor(vendor: string): string | null { + if (!vendor || this.vendorOptions?.length === 0) { + return vendor; + } + return this.vendorOptions?.find((option) => option.toLowerCase() === vendor.toLowerCase()) || null; + } } diff --git a/src/app/fyle/add-edit-expense/add-edit-expense.setup.spec.ts b/src/app/fyle/add-edit-expense/add-edit-expense.setup.spec.ts index 53e9e3ab34..eeade6fa19 100644 --- a/src/app/fyle/add-edit-expense/add-edit-expense.setup.spec.ts +++ b/src/app/fyle/add-edit-expense/add-edit-expense.setup.spec.ts @@ -64,6 +64,7 @@ import { AdvanceWalletsService } from 'src/app/core/services/platform/v1/spender import { PAGINATION_SIZE } from 'src/app/constants'; import { SpenderService } from 'src/app/core/services/platform/v1/spender/spender.service'; import { CostCentersService } from 'src/app/core/services/cost-centers.service'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; export function setFormValid(component) { Object.defineProperty(component.fg, 'valid', { @@ -79,7 +80,7 @@ describe('AddEditExpensePage', () => { 'getPaymentModesWithAdvanceWallets', 'getEtxnSelectedPaymentMode', ]); - const authServiceSpy = jasmine.createSpyObj('AuthService', ['getEou']); + const authServiceSpy = jasmine.createSpyObj('AuthService', ['getEou', 'getRoles']); const categoriesServiceSpy = jasmine.createSpyObj('CategoriesService', [ 'getAll', 'filterRequired', @@ -228,7 +229,7 @@ describe('AddEditExpensePage', () => { TestBed.configureTestingModule({ declarations: [AddEditExpensePage, MaskNumber, FySelectComponent, EllipsisPipe, DependentFieldComponent], - imports: [IonicModule.forRoot(), RouterTestingModule, RouterModule], + imports: [HttpClientTestingModule, IonicModule.forRoot(), RouterTestingModule, RouterModule], providers: [ FormBuilder, { diff --git a/src/app/fyle/my-create-report/my-create-report.page.spec.ts b/src/app/fyle/my-create-report/my-create-report.page.spec.ts index 2812aa54b6..4f45c2a5d4 100644 --- a/src/app/fyle/my-create-report/my-create-report.page.spec.ts +++ b/src/app/fyle/my-create-report/my-create-report.page.spec.ts @@ -18,7 +18,6 @@ import { } from 'src/app/core/mock-data/platform/v1/expense.data'; import { CurrencyService } from 'src/app/core/services/currency.service'; import { LoaderService } from 'src/app/core/services/loader.service'; -import { RefinerService } from 'src/app/core/services/refiner.service'; import { TransactionService } from 'src/app/core/services/transaction.service'; import { FyCurrencyPipe } from 'src/app/shared/pipes/fy-currency.pipe'; import { HumanizeCurrencyPipe } from 'src/app/shared/pipes/humanize-currency.pipe'; @@ -42,7 +41,6 @@ describe('MyCreateReportPage', () => { let router: jasmine.SpyObj; let trackingService: jasmine.SpyObj; let storageService: jasmine.SpyObj; - let refinerService: jasmine.SpyObj; let expensesService: jasmine.SpyObj; let orgSettingsService: jasmine.SpyObj; let spenderReportsService: jasmine.SpyObj; @@ -55,7 +53,6 @@ describe('MyCreateReportPage', () => { const routerSpy = jasmine.createSpyObj('Router', ['navigate']); const trackingServiceSpy = jasmine.createSpyObj('TrackingService', ['createFirstReport', 'createReport']); const storageServiceSpy = jasmine.createSpyObj('StorageService', ['get', 'set']); - const refinerServiceSpy = jasmine.createSpyObj('RefinerService', ['startSurvey']); const expensesServiceSpy = jasmine.createSpyObj('ExpensesService', ['getAllExpenses']); const spenderReportsServiceSpy = jasmine.createSpyObj('SpenderReportsService', [ 'addExpenses', @@ -109,10 +106,6 @@ describe('MyCreateReportPage', () => { provide: StorageService, useValue: storageServiceSpy, }, - { - provide: RefinerService, - useValue: refinerServiceSpy, - }, { provide: ExpensesService, useValue: expensesServiceSpy, @@ -134,7 +127,6 @@ describe('MyCreateReportPage', () => { router = TestBed.inject(Router) as jasmine.SpyObj; trackingService = TestBed.inject(TrackingService) as jasmine.SpyObj; storageService = TestBed.inject(StorageService) as jasmine.SpyObj; - refinerService = TestBed.inject(RefinerService) as jasmine.SpyObj; expensesService = TestBed.inject(ExpensesService) as jasmine.SpyObj; spenderReportsService = TestBed.inject(SpenderReportsService) as jasmine.SpyObj; @@ -277,7 +269,6 @@ describe('MyCreateReportPage', () => { Report_Value: component.selectedTotalAmount, }); expect(router.navigate).toHaveBeenCalledOnceWith(['/', 'enterprise', 'my_reports']); - expect(refinerService.startSurvey).toHaveBeenCalledOnceWith({ actionName: 'Submit Newly Created Report' }); }); it('show report name error if there is no name', fakeAsync(() => { diff --git a/src/app/fyle/my-create-report/my-create-report.page.ts b/src/app/fyle/my-create-report/my-create-report.page.ts index 082abcc24d..5cc91ccb0a 100644 --- a/src/app/fyle/my-create-report/my-create-report.page.ts +++ b/src/app/fyle/my-create-report/my-create-report.page.ts @@ -6,7 +6,6 @@ import { finalize, map, shareReplay, switchMap, tap } from 'rxjs/operators'; import { Expense } from 'src/app/core/models/expense.model'; import { CurrencyService } from 'src/app/core/services/currency.service'; import { LoaderService } from 'src/app/core/services/loader.service'; -import { RefinerService } from 'src/app/core/services/refiner.service'; import { TransactionService } from 'src/app/core/services/transaction.service'; import { StorageService } from '../../core/services/storage.service'; import { TrackingService } from '../../core/services/tracking.service'; @@ -58,7 +57,6 @@ export class MyCreateReportPage implements OnInit { private router: Router, private trackingService: TrackingService, private storageService: StorageService, - private refinerService: RefinerService, private expensesService: ExpensesService, private orgSettingsService: OrgSettingsService, private spenderReportsService: SpenderReportsService @@ -158,8 +156,6 @@ export class MyCreateReportPage implements OnInit { finalize(() => { this.saveReportLoading = false; this.router.navigate(['/', 'enterprise', 'my_reports']); - - this.refinerService.startSurvey({ actionName: 'Submit Newly Created Report' }); }) ) .subscribe(noop); diff --git a/src/app/fyle/my-view-report/my-view-report.page.spec.ts b/src/app/fyle/my-view-report/my-view-report.page.spec.ts index d9f0277865..add7003fe6 100644 --- a/src/app/fyle/my-view-report/my-view-report.page.spec.ts +++ b/src/app/fyle/my-view-report/my-view-report.page.spec.ts @@ -19,7 +19,6 @@ import { AuthService } from 'src/app/core/services/auth.service'; import { LoaderService } from 'src/app/core/services/loader.service'; import { ModalPropertiesService } from 'src/app/core/services/modal-properties.service'; import { OrgSettingsService } from 'src/app/core/services/org-settings.service'; -import { RefinerService } from 'src/app/core/services/refiner.service'; import { ReportService } from 'src/app/core/services/report.service'; import { SnackbarPropertiesService } from 'src/app/core/services/snackbar-properties.service'; import { StatusService } from 'src/app/core/services/status.service'; @@ -78,7 +77,6 @@ describe('MyViewReportPage', () => { let matSnackBar: jasmine.SpyObj; let snackbarProperties: jasmine.SpyObj; let statusService: jasmine.SpyObj; - let refinerService: jasmine.SpyObj; let orgSettingsService: jasmine.SpyObj; let spenderReportsService: jasmine.SpyObj; @@ -109,7 +107,6 @@ describe('MyViewReportPage', () => { const matSnackBarSpy = jasmine.createSpyObj('MatSnackBar', ['openFromComponent']); const snackbarPropertiesSpy = jasmine.createSpyObj('SnackbarPropertiesService', ['setSnackbarProperties']); const statusServiceSpy = jasmine.createSpyObj('StatusService', ['find', 'createStatusMap', 'post']); - const refinerServiceSpy = jasmine.createSpyObj('RefinerService', ['startSurvey']); const orgSettingsServiceSpy = jasmine.createSpyObj('OrgSettingsService', ['get']); const spenderReportsServiceSpy = jasmine.createSpyObj('SpenderReportsService', [ 'addExpenses', @@ -199,10 +196,6 @@ describe('MyViewReportPage', () => { provide: StatusService, useValue: statusServiceSpy, }, - { - provide: RefinerService, - useValue: refinerServiceSpy, - }, { provide: OrgSettingsService, useValue: orgSettingsServiceSpy, @@ -231,7 +224,6 @@ describe('MyViewReportPage', () => { trackingService = TestBed.inject(TrackingService) as jasmine.SpyObj; matSnackBar = TestBed.inject(MatSnackBar) as jasmine.SpyObj; statusService = TestBed.inject(StatusService) as jasmine.SpyObj; - refinerService = TestBed.inject(RefinerService) as jasmine.SpyObj; orgSettingsService = TestBed.inject(OrgSettingsService) as jasmine.SpyObj; spenderReportsService = TestBed.inject(SpenderReportsService) as jasmine.SpyObj; @@ -636,7 +628,6 @@ describe('MyViewReportPage', () => { click(resubmitButton); expect(spenderReportsService.resubmit).toHaveBeenCalledWith(component.reportId); - expect(refinerService.startSurvey).toHaveBeenCalledOnceWith({ actionName: 'Resubmit Report ' }); expect(router.navigate).toHaveBeenCalledOnceWith(['/', 'enterprise', 'my_reports']); expect(matSnackBar.openFromComponent).toHaveBeenCalledOnceWith(ToastMessageComponent, { ...properties, @@ -671,7 +662,6 @@ describe('MyViewReportPage', () => { click(submitButton); expect(spenderReportsService.submit).toHaveBeenCalledWith(component.reportId); - expect(refinerService.startSurvey).toHaveBeenCalledOnceWith({ actionName: 'Submit Report' }); expect(router.navigate).toHaveBeenCalledOnceWith(['/', 'enterprise', 'my_reports']); expect(matSnackBar.openFromComponent).toHaveBeenCalledOnceWith(ToastMessageComponent, { ...properties, diff --git a/src/app/fyle/my-view-report/my-view-report.page.ts b/src/app/fyle/my-view-report/my-view-report.page.ts index 0151878cbf..47b3905dad 100644 --- a/src/app/fyle/my-view-report/my-view-report.page.ts +++ b/src/app/fyle/my-view-report/my-view-report.page.ts @@ -19,7 +19,6 @@ import * as dayjs from 'dayjs'; import { StatusService } from 'src/app/core/services/status.service'; import { ExtendedStatus } from 'src/app/core/models/extended_status.model'; import { cloneDeep } from 'lodash'; -import { RefinerService } from 'src/app/core/services/refiner.service'; import { Expense } from 'src/app/core/models/platform/v1/expense.model'; import { ExpenseView } from 'src/app/core/models/expense-view.enum'; import { OrgSettingsService } from 'src/app/core/services/org-settings.service'; @@ -128,7 +127,6 @@ export class MyViewReportPage { private matSnackBar: MatSnackBar, private snackbarProperties: SnackbarPropertiesService, private statusService: StatusService, - private refinerService: RefinerService, private orgSettingsService: OrgSettingsService, private platformHandlerService: PlatformHandlerService, private spenderReportsService: SpenderReportsService @@ -435,7 +433,6 @@ export class MyViewReportPage { resubmitReport(): void { this.spenderReportsService.resubmit(this.reportId).subscribe(() => { - this.refinerService.startSurvey({ actionName: 'Resubmit Report ' }); this.router.navigate(['/', 'enterprise', 'my_reports']); const message = `Report resubmitted successfully.`; this.matSnackBar.openFromComponent(ToastMessageComponent, { @@ -448,7 +445,6 @@ export class MyViewReportPage { submitReport(): void { this.spenderReportsService.submit(this.reportId).subscribe(() => { - this.refinerService.startSurvey({ actionName: 'Submit Report' }); this.router.navigate(['/', 'enterprise', 'my_reports']); const message = `Report submitted successfully.`; this.matSnackBar.openFromComponent(ToastMessageComponent, { diff --git a/src/app/fyle/view-team-report/view-team-report.page.spec.ts b/src/app/fyle/view-team-report/view-team-report.page.spec.ts index 00d39bd323..22722fe61e 100644 --- a/src/app/fyle/view-team-report/view-team-report.page.spec.ts +++ b/src/app/fyle/view-team-report/view-team-report.page.spec.ts @@ -16,7 +16,6 @@ import { LoaderService } from 'src/app/core/services/loader.service'; import { ModalPropertiesService } from 'src/app/core/services/modal-properties.service'; import { OrgSettingsService } from 'src/app/core/services/org-settings.service'; import { PopupService } from 'src/app/core/services/popup.service'; -import { RefinerService } from 'src/app/core/services/refiner.service'; import { ReportService } from 'src/app/core/services/report.service'; import { SnackbarPropertiesService } from 'src/app/core/services/snackbar-properties.service'; import { StatusService } from 'src/app/core/services/status.service'; @@ -56,6 +55,8 @@ import { import { ExpensesService as ApproverExpensesService } from 'src/app/core/services/platform/v1/approver/expenses.service'; import { FyViewReportInfoComponent } from 'src/app/shared/components/fy-view-report-info/fy-view-report-info.component'; import { ApproverReportsService } from 'src/app/core/services/platform/v1/approver/reports.service'; +import { LaunchDarklyService } from 'src/app/core/services/launch-darkly.service'; +import { RefinerService } from 'src/app/core/services/refiner.service'; describe('ViewTeamReportPageV2', () => { let component: ViewTeamReportPage; @@ -74,11 +75,12 @@ describe('ViewTeamReportPageV2', () => { let trackingService: jasmine.SpyObj; let matSnackBar: jasmine.SpyObj; let snackbarProperties: jasmine.SpyObj; - let refinerService: jasmine.SpyObj; let statusService: jasmine.SpyObj; let humanizeCurrency: jasmine.SpyObj; let orgSettingsService: jasmine.SpyObj; let approverReportsService: jasmine.SpyObj; + let launchDarklyService: jasmine.SpyObj; + let refinerService: jasmine.SpyObj; beforeEach(waitForAsync(() => { const approverExpensesServiceSpy = jasmine.createSpyObj('ApproverExpensesService', [ @@ -103,7 +105,6 @@ describe('ViewTeamReportPageV2', () => { ]); const matSnackBarSpy = jasmine.createSpyObj('MatSnackBar', ['openFromComponent']); const snackbarPropertiesSpy = jasmine.createSpyObj('SnackbarPropertiesService', ['setSnackbarProperties']); - const refinerServiceSpy = jasmine.createSpyObj('RefinerService', ['startSurvey', '']); const statusServiceSpy = jasmine.createSpyObj('StatusService', ['find', 'createStatusMap', 'post']); const humanizeCurrencySpy = jasmine.createSpyObj('HumanizeCurrencyPipe', ['transform']); const orgSettingsServiceSpy = jasmine.createSpyObj('OrgSettingsService', ['get']); @@ -114,6 +115,8 @@ describe('ViewTeamReportPageV2', () => { 'sendBack', 'approve', ]); + launchDarklyService = jasmine.createSpyObj('LaunchDarklyService', ['getVariation']); + refinerService = jasmine.createSpyObj('RefinerService', ['startSurvey']); TestBed.configureTestingModule({ declarations: [ViewTeamReportPage, EllipsisPipe, HumanizeCurrencyPipe], @@ -176,6 +179,14 @@ describe('ViewTeamReportPageV2', () => { provide: TrackingService, useValue: trackingServiceSpy, }, + { + provide: LaunchDarklyService, + useValue: launchDarklyService, + }, + { + provide: RefinerService, + useValue: refinerService, + }, { provide: MatSnackBar, useValue: matSnackBarSpy, @@ -184,10 +195,6 @@ describe('ViewTeamReportPageV2', () => { provide: SnackbarPropertiesService, useValue: snackbarPropertiesSpy, }, - { - provide: RefinerService, - useValue: refinerServiceSpy, - }, { provide: StatusService, useValue: statusServiceSpy, @@ -224,11 +231,12 @@ describe('ViewTeamReportPageV2', () => { trackingService = TestBed.inject(TrackingService) as jasmine.SpyObj; matSnackBar = TestBed.inject(MatSnackBar) as jasmine.SpyObj; snackbarProperties = TestBed.inject(SnackbarPropertiesService) as jasmine.SpyObj; - refinerService = TestBed.inject(RefinerService) as jasmine.SpyObj; statusService = TestBed.inject(StatusService) as jasmine.SpyObj; humanizeCurrency = TestBed.inject(HumanizeCurrencyPipe) as jasmine.SpyObj; orgSettingsService = TestBed.inject(OrgSettingsService) as jasmine.SpyObj; approverReportsService = TestBed.inject(ApproverReportsService) as jasmine.SpyObj; + launchDarklyService = TestBed.inject(LaunchDarklyService) as jasmine.SpyObj; + refinerService = TestBed.inject(RefinerService) as jasmine.SpyObj; fixture.detectChanges(); })); @@ -270,6 +278,22 @@ describe('ViewTeamReportPageV2', () => { expect(result).toBeFalse(); }); + it('should return true if approval settings are enabled', () => { + const result = component.getApprovalSettings({ + ...orgSettingsData, + approval_settings: { enable_sequential_approvers: true }, + }); + expect(result).toBeTrue(); + }); + + it('should return false if approval settings are disabled', () => { + const result = component.getApprovalSettings({ + ...orgSettingsData, + approval_settings: { enable_sequential_approvers: false }, + }); + expect(result).toBeFalse(); + }); + it('should return undefined if approval settings not present', () => { const result = component.getApprovalSettings({ ...orgSettingsData, approval_settings: undefined }); expect(result).toBeUndefined(); @@ -497,6 +521,23 @@ describe('ViewTeamReportPageV2', () => { component.setupComments({ ...platformReportData, comments: null }); expect(component.estatuses).toEqual([]); }); + + it('should handle comments when user is not present', () => { + component.eou$ = of(null); + component.setupComments({ + ...platformReportData, + comments: [ + { + creator_user_id: 'other', + comment: '', + created_at: undefined, + creator_user: null, + id: '', + }, + ], + }); + expect(component.estatuses.length).toBe(1); + }); }); it('setupNetworkWatcher(): should setup network watcher', () => { @@ -524,7 +565,7 @@ describe('ViewTeamReportPageV2', () => { }); describe('approveReport(): ', () => { - it('should open the modal and approve the report', async () => { + it('should open the modal and approve the report', fakeAsync(() => { humanizeCurrency.transform.and.callThrough(); const popoverSpy = jasmine.createSpyObj('popover', ['present', 'onWillDismiss']); popoverSpy.onWillDismiss.and.resolveTo({ @@ -535,13 +576,14 @@ describe('ViewTeamReportPageV2', () => { popoverController.create.and.resolveTo(popoverSpy); approverReportsService.approve.and.returnValue(of(undefined)); - refinerService.startSurvey.and.returnValue(null); component.report$ = of(reportWithExpenses); component.expenses$ = of(expenseResponseData); + launchDarklyService.getVariation.and.returnValue(of(true)); fixture.detectChanges(); - await component.approveReport(); + component.approveReport(); + tick(1000); expect(popoverController.create).toHaveBeenCalledOnceWith({ componentProps: { @@ -566,18 +608,103 @@ describe('ViewTeamReportPageV2', () => { false ); expect(approverReportsService.approve).toHaveBeenCalledOnceWith(platformReportData.id); - expect(refinerService.startSurvey).toHaveBeenCalledOnceWith({ actionName: 'Approve Report' }); expect(router.navigate).toHaveBeenCalledOnceWith(['/', 'enterprise', 'team_reports']); - }); + expect(launchDarklyService.getVariation).toHaveBeenCalledOnceWith('nps_survey', false); + expect(refinerService.startSurvey).toHaveBeenCalledOnceWith({ actionName: 'Approve Report' }); + })); - it('should toggle tooltip if approval priviledge is not provided', async () => { + it('should toggle tooltip if approval permission is not provided', fakeAsync(() => { spyOn(component, 'toggleTooltip'); component.canApprove = false; fixture.detectChanges(); - await component.approveReport(); + component.approveReport(); + tick(); + expect(component.toggleTooltip).toHaveBeenCalledTimes(1); - }); + })); + + it('should not approve report if user does not have approval permissions', fakeAsync(() => { + component.canApprove = false; + component.approveReport(); + tick(); + + expect(router.navigate).not.toHaveBeenCalled(); + })); + + it('should not approve report if user cancels the popover', fakeAsync(() => { + const popoverSpy = jasmine.createSpyObj('popover', ['present', 'onWillDismiss']); + popoverSpy.onWillDismiss.and.resolveTo({ + data: { + action: 'cancel', + }, + }); + + popoverController.create.and.resolveTo(popoverSpy); + + component.report$ = of(reportWithExpenses); + component.expenses$ = of(expenseResponseData); + fixture.detectChanges(); + + component.approveReport(); + tick(); + + expect(popoverController.create).toHaveBeenCalledOnceWith(jasmine.any(Object)); + expect(approverReportsService.approve).not.toHaveBeenCalled(); + expect(router.navigate).not.toHaveBeenCalled(); + expect(launchDarklyService.getVariation).not.toHaveBeenCalled(); + expect(refinerService.startSurvey).not.toHaveBeenCalled(); + })); + + it('should not start NPS survey if feature flag is disabled', fakeAsync(() => { + const popoverSpy = jasmine.createSpyObj('popover', ['present', 'onWillDismiss']); + popoverSpy.onWillDismiss.and.resolveTo({ + data: { + action: 'approve', + }, + }); + + popoverController.create.and.resolveTo(popoverSpy); + approverReportsService.approve.and.returnValue(of(undefined)); + launchDarklyService.getVariation.and.returnValue(of(false)); + + component.report$ = of(reportWithExpenses); + component.expenses$ = of(expenseResponseData); + fixture.detectChanges(); + + component.approveReport(); + tick(); + + expect(approverReportsService.approve).toHaveBeenCalledOnceWith(platformReportData.id); + expect(router.navigate).toHaveBeenCalledOnceWith(['/', 'enterprise', 'team_reports']); + expect(launchDarklyService.getVariation).toHaveBeenCalledOnceWith('nps_survey', false); + expect(refinerService.startSurvey).not.toHaveBeenCalled(); + })); + + it('should start NPS survey if feature flag is enabled', fakeAsync(() => { + const popoverSpy = jasmine.createSpyObj('popover', ['present', 'onWillDismiss']); + popoverSpy.onWillDismiss.and.resolveTo({ + data: { + action: 'approve', + }, + }); + + popoverController.create.and.resolveTo(popoverSpy); + approverReportsService.approve.and.returnValue(of(undefined)); + launchDarklyService.getVariation.and.returnValue(of(true)); + + component.report$ = of(reportWithExpenses); + component.expenses$ = of(expenseResponseData); + fixture.detectChanges(); + + component.approveReport(); + tick(); + + expect(approverReportsService.approve).toHaveBeenCalledOnceWith(platformReportData.id); + expect(router.navigate).toHaveBeenCalledOnceWith(['/', 'enterprise', 'team_reports']); + expect(launchDarklyService.getVariation).toHaveBeenCalledOnceWith('nps_survey', false); + expect(refinerService.startSurvey).toHaveBeenCalledOnceWith({ actionName: 'Approve Report' }); + })); }); it('onUpdateApprover(): should refresh approval on approver update', () => { @@ -707,7 +834,6 @@ describe('ViewTeamReportPageV2', () => { expect(trackingService.showToastMessage).toHaveBeenCalledOnceWith({ ToastContent: 'Report Sent Back successfully', }); - expect(refinerService.startSurvey).toHaveBeenCalledOnceWith({ actionName: 'Send Back Report' }); expect(router.navigate).toHaveBeenCalledOnceWith(['/', 'enterprise', 'team_reports']); }); diff --git a/src/app/fyle/view-team-report/view-team-report.page.ts b/src/app/fyle/view-team-report/view-team-report.page.ts index 118523794a..a81e4792c1 100644 --- a/src/app/fyle/view-team-report/view-team-report.page.ts +++ b/src/app/fyle/view-team-report/view-team-report.page.ts @@ -14,7 +14,6 @@ import { MatSnackBar } from '@angular/material/snack-bar'; import { ToastMessageComponent } from 'src/app/shared/components/toast-message/toast-message.component'; import { SnackbarPropertiesService } from 'src/app/core/services/snackbar-properties.service'; import { FyPopoverComponent } from 'src/app/shared/components/fy-popover/fy-popover.component'; -import { RefinerService } from 'src/app/core/services/refiner.service'; import { ExpenseView } from 'src/app/core/models/expense-view.enum'; import { getCurrencySymbol } from '@angular/common'; import * as dayjs from 'dayjs'; @@ -35,6 +34,8 @@ import { OrgSettings } from 'src/app/core/models/org-settings.model'; import { ExtendedComment } from 'src/app/core/models/platform/v1/extended-comment.model'; import { Comment } from 'src/app/core/models/platform/v1/comment.model'; import { ApprovalState, ReportApprovals } from 'src/app/core/models/platform/report-approvals.model'; +import { LaunchDarklyService } from 'src/app/core/services/launch-darkly.service'; +import { RefinerService } from 'src/app/core/services/refiner.service'; @Component({ selector: 'app-view-team-report', @@ -142,8 +143,9 @@ export class ViewTeamReportPage { private modalProperties: ModalPropertiesService, private trackingService: TrackingService, private matSnackBar: MatSnackBar, - private snackbarProperties: SnackbarPropertiesService, + private launchDarklyService: LaunchDarklyService, private refinerService: RefinerService, + private snackbarProperties: SnackbarPropertiesService, private statusService: StatusService, private humanizeCurrency: HumanizeCurrencyPipe, private orgSettingsService: OrgSettingsService, @@ -377,8 +379,12 @@ export class ViewTeamReportPage { if (data && data.action === 'approve') { this.approverReportsService.approve(report.id).subscribe(() => { - this.refinerService.startSurvey({ actionName: 'Approve Report' }); this.router.navigate(['/', 'enterprise', 'team_reports']); + this.launchDarklyService.getVariation('nps_survey', false).subscribe((showNpsSurvey) => { + if (showNpsSurvey) { + this.refinerService.startSurvey({ actionName: 'Approve Report' }); + } + }); }); } } @@ -436,7 +442,6 @@ export class ViewTeamReportPage { panelClass: ['msb-success-with-camera-icon'], }); this.trackingService.showToastMessage({ ToastContent: message }); - this.refinerService.startSurvey({ actionName: 'Send Back Report' }); }); this.router.navigate(['/', 'enterprise', 'team_reports']); } diff --git a/src/app/shared/components/create-new-report-v2/create-new-report.component.spec.ts b/src/app/shared/components/create-new-report-v2/create-new-report.component.spec.ts index a01c4a0e86..10a73f0aa8 100644 --- a/src/app/shared/components/create-new-report-v2/create-new-report.component.spec.ts +++ b/src/app/shared/components/create-new-report-v2/create-new-report.component.spec.ts @@ -5,7 +5,6 @@ import { MatIconTestingModule } from '@angular/material/icon/testing'; import { HumanizeCurrencyPipe } from '../../pipes/humanize-currency.pipe'; import { ModalController } from '@ionic/angular'; import { TrackingService } from 'src/app/core/services/tracking.service'; -import { RefinerService } from 'src/app/core/services/refiner.service'; import { CurrencyService } from 'src/app/core/services/currency.service'; import { ExpenseFieldsService } from 'src/app/core/services/expense-fields.service'; import { CreateNewReportComponent } from './create-new-report.component'; @@ -26,7 +25,6 @@ describe('CreateNewReportComponent', () => { let fixture: ComponentFixture; let modalController: jasmine.SpyObj; let trackingService: jasmine.SpyObj; - let refinerService: jasmine.SpyObj; let currencyService: jasmine.SpyObj; let expenseFieldsService: jasmine.SpyObj; let spenderReportsService: jasmine.SpyObj; @@ -34,7 +32,6 @@ describe('CreateNewReportComponent', () => { beforeEach(waitForAsync(() => { modalController = jasmine.createSpyObj('ModalController', ['dismiss']); trackingService = jasmine.createSpyObj('TrackingService', ['createReport']); - refinerService = jasmine.createSpyObj('RefinerService', ['startSurvey']); currencyService = jasmine.createSpyObj('CurrencyService', ['getHomeCurrency']); expenseFieldsService = jasmine.createSpyObj('ExpenseFieldsService', ['getAllMap']); spenderReportsService = jasmine.createSpyObj('SpenderReportsService', [ @@ -59,7 +56,6 @@ describe('CreateNewReportComponent', () => { providers: [ { provide: ModalController, useValue: modalController }, { provide: TrackingService, useValue: trackingService }, - { provide: RefinerService, useValue: refinerService }, { provide: CurrencyService, useValue: currencyService }, { provide: ExpenseFieldsService, useValue: expenseFieldsService }, { provide: HumanizeCurrencyPipe, useValue: humanizeCurrencyPipeSpy }, @@ -70,7 +66,6 @@ describe('CreateNewReportComponent', () => { }).compileComponents(); trackingService = TestBed.inject(TrackingService) as jasmine.SpyObj; - refinerService = TestBed.inject(RefinerService) as jasmine.SpyObj; currencyService = TestBed.inject(CurrencyService) as jasmine.SpyObj; expenseFieldsService = TestBed.inject(ExpenseFieldsService) as jasmine.SpyObj; spenderReportsService = TestBed.inject(SpenderReportsService) as jasmine.SpyObj; @@ -200,7 +195,7 @@ describe('CreateNewReportComponent', () => { const Expense_Count = txns.length; const Report_Value = 0; const report = expectedReportsSinglePage[0]; - spenderReportsService.createDraft.and.returnValue(of(expectedReportsSinglePage[0])); + spenderReportsService.createDraft.and.returnValue(of(report)); spenderReportsService.addExpenses.and.returnValue(of(undefined)); component.ctaClickedEvent('create_draft_report'); fixture.detectChanges(); @@ -230,7 +225,7 @@ describe('CreateNewReportComponent', () => { const Expense_Count = tnxs.length; const Report_Value = 0; const report = expectedReportsSinglePage[0]; - spenderReportsService.createDraft.and.returnValue(of(expectedReportsSinglePage[0])); + spenderReportsService.createDraft.and.returnValue(of(report)); component.ctaClickedEvent('create_draft_report'); fixture.detectChanges(); tick(500); @@ -251,17 +246,17 @@ describe('CreateNewReportComponent', () => { purpose: '#3 : Mar 2023', source: 'MOBILE', }; - const txnIds = ['txDDLtRaflUW', 'tx5WDG9lxBDT']; const report = expectedReportsSinglePage[0]; - spenderReportsService.create.and.returnValue(of(expectedReportsSinglePage[0])); - component.ctaClickedEvent('submit_report'); + + spenderReportsService.create.and.returnValue(of(report)); fixture.detectChanges(); + + component.ctaClickedEvent('submit_report'); tick(500); expect(component.submitReportLoader).toBeFalse(); expect(component.showReportNameError).toBeFalse(); expect(spenderReportsService.create).toHaveBeenCalledOnceWith(reportPurpose, txnIds); - expect(refinerService.startSurvey).toHaveBeenCalledOnceWith({ actionName: 'Submit Newly Created Report' }); expect(component.submitReportLoader).toBeFalse(); expect(modalController.dismiss).toHaveBeenCalledOnceWith({ report, diff --git a/src/app/shared/components/create-new-report-v2/create-new-report.component.ts b/src/app/shared/components/create-new-report-v2/create-new-report.component.ts index ed818646af..ba63dd6b14 100644 --- a/src/app/shared/components/create-new-report-v2/create-new-report.component.ts +++ b/src/app/shared/components/create-new-report-v2/create-new-report.component.ts @@ -6,7 +6,6 @@ import { finalize, map, switchMap, tap } from 'rxjs/operators'; import { Expense } from 'src/app/core/models/platform/v1/expense.model'; import { ExpenseFieldsMap } from 'src/app/core/models/v1/expense-fields-map.model'; import { TrackingService } from 'src/app/core/services/tracking.service'; -import { RefinerService } from 'src/app/core/services/refiner.service'; import { CurrencyService } from 'src/app/core/services/currency.service'; import { ExpenseFieldsService } from 'src/app/core/services/expense-fields.service'; import { SpenderReportsService } from 'src/app/core/services/platform/v1/spender/reports.service'; @@ -43,7 +42,6 @@ export class CreateNewReportComponent implements OnInit { constructor( private modalController: ModalController, private trackingService: TrackingService, - private refinerService: RefinerService, private currencyService: CurrencyService, private expenseFieldsService: ExpenseFieldsService, private spenderReportsService: SpenderReportsService @@ -103,7 +101,7 @@ export class CreateNewReportComponent implements OnInit { this.modalController.dismiss(); } - ctaClickedEvent(reportActionType): Subscription { + async ctaClickedEvent(reportActionType: string): Promise { this.showReportNameError = false; if (this.reportTitle.trim().length <= 0) { this.showReportNameError = true; @@ -118,7 +116,7 @@ export class CreateNewReportComponent implements OnInit { const txnIds = this.selectedElements.map((expense) => expense.id); if (reportActionType === 'create_draft_report') { this.saveDraftReportLoader = true; - return this.spenderReportsService + this.spenderReportsService .createDraft({ data: report }) .pipe( tap(() => @@ -154,7 +152,6 @@ export class CreateNewReportComponent implements OnInit { Expense_Count: txnIds.length, Report_Value: this.selectedTotalAmount, }); - this.refinerService.startSurvey({ actionName: 'Submit Newly Created Report' }); }), finalize(() => { this.submitReportLoader = false; diff --git a/src/environments/environment.ts b/src/environments/environment.ts index 03f30a5082..8e8f3e0bf1 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -13,6 +13,7 @@ export const environment = { GOOGLE_MAPS_API_KEY: '', FRESHCHAT_TOKEN: '', SENTRY_DSN: '', + REFINER_NPS_PROJECT_ID: '', REFINER_NPS_FORM_ID: '', LAUNCH_DARKLY_CLIENT_ID: '', LIVE_UPDATE_APP_VERSION: '', diff --git a/src/index.html b/src/index.html index 249d8fef40..a16b1d36d1 100644 --- a/src/index.html +++ b/src/index.html @@ -26,5 +26,21 @@ + + +