From 893d016c34df8b495de6914ec5983769ed514105 Mon Sep 17 00:00:00 2001 From: Chethan-Fyle <93918979+Chethan-Fyle@users.noreply.github.com> Date: Wed, 29 May 2024 11:23:09 +0530 Subject: [PATCH] feat: delete attachment using platform api (#3029) --- src/app/core/mock-data/receipt-info.data.ts | 4 + .../platform/v1/spender/file.service.ts | 6 ++ .../add-edit-expense/add-edit-expense.page.ts | 13 ++- .../fyle/view-mileage/view-mileage.page.ts | 2 + .../fy-view-attachment.component.spec.ts | 30 +++--- .../fy-view-attachment.component.ts | 91 +++++++++---------- 6 files changed, 79 insertions(+), 67 deletions(-) diff --git a/src/app/core/mock-data/receipt-info.data.ts b/src/app/core/mock-data/receipt-info.data.ts index 2b9cc3146d..22f564f174 100644 --- a/src/app/core/mock-data/receipt-info.data.ts +++ b/src/app/core/mock-data/receipt-info.data.ts @@ -2,6 +2,8 @@ import deepFreeze from 'deep-freeze-strict'; import { ReceiptInfo } from '../models/receipt-info.model'; export const receiptInfoData1: ReceiptInfo = deepFreeze({ + id: '1', + name: 'invoice.pdf', type: 'pdf', url: 'https://sampledownloadurl.com', thumbnail: 'img/fy-pdf.svg', @@ -9,6 +11,8 @@ export const receiptInfoData1: ReceiptInfo = deepFreeze({ export const receiptInfoData2: ReceiptInfo[] = deepFreeze([ { + id: '1', + name: 'invoice.pdf', type: 'pdf', url: 'https://sampledownloadurl.com', thumbnail: 'img/fy-pdf.svg', diff --git a/src/app/core/services/platform/v1/spender/file.service.ts b/src/app/core/services/platform/v1/spender/file.service.ts index 0687e91064..cf6d976c50 100644 --- a/src/app/core/services/platform/v1/spender/file.service.ts +++ b/src/app/core/services/platform/v1/spender/file.service.ts @@ -26,6 +26,12 @@ export class SpenderFileService { .pipe(map((response) => response.data)); } + deleteFilesBulk(fileIds: string[]): Observable<{}> { + const data = fileIds.map((id) => ({ id })); + const payload = { data }; + return this.spenderPlatformV1ApiService.post('/files/delete/bulk', payload); + } + generateUrls(id: string): Observable { const payload = { data: { id }, 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 041fbb3078..fd01d12139 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 @@ -136,7 +136,6 @@ import { CorporateCardTransactionRes } from 'src/app/core/models/platform/v1/cor import { corporateCardTransaction } from 'src/app/core/models/platform/v1/cc-transaction.model'; 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 { ReceiptInfo } from 'src/app/core/models/receipt-info.model'; type FormValue = { currencyObj: { @@ -3104,10 +3103,12 @@ export class AddEditExpensePage implements OnInit { ), map((response: PlatformFileGenerateUrlsResponse[]) => { const files = response.filter((file) => file.content_type !== 'text/html'); - const receiptObjs: ReceiptInfo[] = files.map((file) => { + const receiptObjs: FileObject[] = files.map((file) => { const details = this.fileService.getReceiptsDetails(file.name, file.download_url); - const receipt: ReceiptInfo = { + const receipt: FileObject = { + id: file.id, + name: file.name, url: file.download_url, type: details.type, thumbnail: details.thumbnail, @@ -3231,10 +3232,12 @@ export class AddEditExpensePage implements OnInit { ), map((response: PlatformFileGenerateUrlsResponse[]) => { const files = response.filter((file) => file.content_type !== 'text/html'); - const receiptObjs: ReceiptInfo[] = files.map((file) => { + const receiptObjs: FileObject[] = files.map((file) => { const details = this.fileService.getReceiptsDetails(file.name, file.download_url); - const receipt: ReceiptInfo = { + const receipt: FileObject = { + id: file.id, + name: file.name, url: file.download_url, type: details.type, thumbnail: details.thumbnail, diff --git a/src/app/fyle/view-mileage/view-mileage.page.ts b/src/app/fyle/view-mileage/view-mileage.page.ts index 66caa41b6c..015219a581 100644 --- a/src/app/fyle/view-mileage/view-mileage.page.ts +++ b/src/app/fyle/view-mileage/view-mileage.page.ts @@ -330,6 +330,8 @@ export class ViewMileagePage { const details = this.fileService.getReceiptsDetails(response.name, response.download_url); const receipt: FileObject = { + id: response.id, + name: response.name, url: response.download_url, type: details.type, thumbnail: details.thumbnail, diff --git a/src/app/shared/components/fy-view-attachment/fy-view-attachment.component.spec.ts b/src/app/shared/components/fy-view-attachment/fy-view-attachment.component.spec.ts index 5ad12b5ea5..5d62d74441 100644 --- a/src/app/shared/components/fy-view-attachment/fy-view-attachment.component.spec.ts +++ b/src/app/shared/components/fy-view-attachment/fy-view-attachment.component.spec.ts @@ -1,9 +1,8 @@ import { ComponentFixture, TestBed, fakeAsync, tick, waitForAsync } from '@angular/core/testing'; import { IonicModule, ModalController, PopoverController } from '@ionic/angular'; - +import { SpenderFileService } from 'src/app/core/services/platform/v1/spender/file.service'; import { FyViewAttachmentComponent } from './fy-view-attachment.component'; import { DomSanitizer } from '@angular/platform-browser'; -import { FileService } from 'src/app/core/services/file.service'; import { LoaderService } from 'src/app/core/services/loader.service'; import { NO_ERRORS_SCHEMA } from '@angular/core'; import { of } from 'rxjs'; @@ -15,7 +14,7 @@ describe('FyViewAttachmentComponent', () => { let domSantizer: jasmine.SpyObj; let modalController: jasmine.SpyObj; let popoverController: jasmine.SpyObj; - let fileService: jasmine.SpyObj; + let spenderFileService: jasmine.SpyObj; let loaderService: jasmine.SpyObj; let trackingService: jasmine.SpyObj; @@ -23,10 +22,9 @@ describe('FyViewAttachmentComponent', () => { const domSantizerSpy = jasmine.createSpyObj('DomSanitizer', ['bypassSecurityTrustUrl']); const modalControllerSpy = jasmine.createSpyObj('ModalController', ['dismiss']); const popoverControllerSpy = jasmine.createSpyObj('PopoverController', ['create']); - const fileServiceSpy = jasmine.createSpyObj('FileService', ['delete']); const loaderServiceSpy = jasmine.createSpyObj('LoaderService', ['hideLoader', 'showLoader']); const trackingServiceSpy = jasmine.createSpyObj('TracingService', ['deleteFileClicked', 'fileDeleted']); - + const spenderFileServiceSpy = jasmine.createSpyObj('SpenderFileService', ['deleteFilesBulk']); TestBed.configureTestingModule({ declarations: [FyViewAttachmentComponent], providers: [ @@ -43,8 +41,8 @@ describe('FyViewAttachmentComponent', () => { useValue: popoverControllerSpy, }, { - provide: FileService, - useValue: fileServiceSpy, + provide: SpenderFileService, + useValue: spenderFileServiceSpy, }, { provide: LoaderService, @@ -64,8 +62,8 @@ describe('FyViewAttachmentComponent', () => { domSantizer = TestBed.inject(DomSanitizer) as jasmine.SpyObj; modalController = TestBed.inject(ModalController) as jasmine.SpyObj; popoverController = TestBed.inject(PopoverController) as jasmine.SpyObj; + spenderFileService = TestBed.inject(SpenderFileService) as jasmine.SpyObj; loaderService = TestBed.inject(LoaderService) as jasmine.SpyObj; - fileService = TestBed.inject(FileService) as jasmine.SpyObj; trackingService = TestBed.inject(TrackingService) as jasmine.SpyObj; const mockAttachments = [ @@ -189,7 +187,7 @@ describe('FyViewAttachmentComponent', () => { }) as any ); - fileService.delete.and.returnValue(of(null)); + spenderFileService.deleteFilesBulk.and.returnValue(of({})); spyOn(component, 'goToPrevSlide'); spyOn(component, 'goToNextSlide'); component.deleteAttachment(); @@ -208,7 +206,7 @@ describe('FyViewAttachmentComponent', () => { url: 'http://example.com/attachment3.pdf', }, ]); - expect(fileService.delete).toHaveBeenCalledOnceWith('2'); + expect(spenderFileService.deleteFilesBulk).toHaveBeenCalledOnceWith(['2']); expect(trackingService.deleteFileClicked).toHaveBeenCalledOnceWith({ 'File ID': '2' }); expect(trackingService.fileDeleted).toHaveBeenCalledOnceWith({ 'File ID': '2' }); })); @@ -232,7 +230,7 @@ describe('FyViewAttachmentComponent', () => { }) as any ); - fileService.delete.and.returnValue(of(null)); + spenderFileService.deleteFilesBulk.and.returnValue(of({})); spyOn(component, 'goToPrevSlide'); spyOn(component, 'goToNextSlide'); component.deleteAttachment(); @@ -251,7 +249,7 @@ describe('FyViewAttachmentComponent', () => { url: 'http://example.com/attachment3.pdf', }, ]); - expect(fileService.delete).toHaveBeenCalledOnceWith('1'); + expect(spenderFileService.deleteFilesBulk).toHaveBeenCalledOnceWith(['1']); expect(trackingService.deleteFileClicked).toHaveBeenCalledOnceWith({ 'File ID': '1' }); expect(trackingService.fileDeleted).toHaveBeenCalledOnceWith({ 'File ID': '1' }); })); @@ -283,7 +281,7 @@ describe('FyViewAttachmentComponent', () => { }) as any ); - fileService.delete.and.returnValue(of(null)); + spenderFileService.deleteFilesBulk.and.returnValue(of({})); spyOn(component, 'goToPrevSlide'); spyOn(component, 'goToNextSlide'); component.deleteAttachment(); @@ -291,7 +289,7 @@ describe('FyViewAttachmentComponent', () => { expect(modalController.dismiss).toHaveBeenCalledOnceWith({ attachments: component.attachments }); expect(component.attachments.length).toBe(0); - expect(fileService.delete).toHaveBeenCalledOnceWith('1'); + expect(spenderFileService.deleteFilesBulk).toHaveBeenCalledOnceWith(['1']); expect(trackingService.deleteFileClicked).toHaveBeenCalledOnceWith({ 'File ID': '1' }); expect(trackingService.fileDeleted).toHaveBeenCalledOnceWith({ 'File ID': '1' }); })); @@ -333,7 +331,7 @@ describe('FyViewAttachmentComponent', () => { }) as any ); - fileService.delete.and.returnValue(of(null)); + spenderFileService.deleteFilesBulk.and.returnValue(of({})); spyOn(component, 'goToPrevSlide'); spyOn(component, 'goToNextSlide'); @@ -353,7 +351,7 @@ describe('FyViewAttachmentComponent', () => { url: 'http://example.com/attachment3.pdf', }, ]); - expect(fileService.delete).not.toHaveBeenCalledOnceWith('2'); + expect(spenderFileService.deleteFilesBulk).not.toHaveBeenCalledOnceWith(['2']); expect(trackingService.deleteFileClicked).toHaveBeenCalledOnceWith({ 'File ID': null }); expect(trackingService.fileDeleted).toHaveBeenCalledOnceWith({ 'File ID': null }); })); diff --git a/src/app/shared/components/fy-view-attachment/fy-view-attachment.component.ts b/src/app/shared/components/fy-view-attachment/fy-view-attachment.component.ts index 5310b9743f..b4f08ca910 100644 --- a/src/app/shared/components/fy-view-attachment/fy-view-attachment.component.ts +++ b/src/app/shared/components/fy-view-attachment/fy-view-attachment.component.ts @@ -1,15 +1,15 @@ import { Component, OnInit, Input, ViewChild } from '@angular/core'; import { ModalController, PopoverController } from '@ionic/angular'; import { DomSanitizer } from '@angular/platform-browser'; -import { PopupService } from 'src/app/core/services/popup.service'; import { LoaderService } from 'src/app/core/services/loader.service'; -import { FileService } from 'src/app/core/services/file.service'; import { from, of } from 'rxjs'; import { switchMap, finalize } from 'rxjs/operators'; import { PopupAlertComponent } from 'src/app/shared/components/popup-alert/popup-alert.component'; import { SwiperComponent } from 'swiper/angular'; -import SwiperCore, { Pagination } from 'swiper'; import { TrackingService } from 'src/app/core/services/tracking.service'; +import { SpenderFileService } from 'src/app/core/services/platform/v1/spender/file.service'; +import { FileObject } from 'src/app/core/models/file-obj.model'; +import { OverlayEventDetail } from '@ionic/core'; @Component({ selector: 'app-fy-view-attachment', @@ -17,7 +17,7 @@ import { TrackingService } from 'src/app/core/services/tracking.service'; styleUrls: ['./fy-view-attachment.component.scss'], }) export class FyViewAttachmentComponent implements OnInit { - @Input() attachments: any[]; + @Input() attachments: FileObject[]; @Input() isMileageExpense: boolean; @@ -25,6 +25,7 @@ export class FyViewAttachmentComponent implements OnInit { @ViewChild('swiper', { static: false }) imageSlides?: SwiperComponent; + // eslint-disable-next-line @typescript-eslint/no-explicit-any sliderOptions: any; activeIndex = 0; @@ -36,13 +37,12 @@ export class FyViewAttachmentComponent implements OnInit { private modalController: ModalController, private popoverController: PopoverController, private sanitizer: DomSanitizer, - private popupService: PopupService, private loaderService: LoaderService, - private fileService: FileService, - private trackingService: TrackingService + private trackingService: TrackingService, + private spenderFileService: SpenderFileService ) {} - ngOnInit() { + ngOnInit(): void { this.zoomScale = 1; this.sliderOptions = { zoom: { @@ -57,39 +57,39 @@ export class FyViewAttachmentComponent implements OnInit { }); } - ionViewWillEnter() { + ionViewWillEnter(): void { this.imageSlides.swiperRef.update(); } - zoomIn() { + zoomIn(): void { this.zoomScale += 0.25; } - zoomOut() { + zoomOut(): void { this.zoomScale -= 0.25; } - resetZoom() { + resetZoom(): void { this.zoomScale = 1; } - onDoneClick() { + onDoneClick(): void { this.modalController.dismiss({ attachments: this.attachments }); } - goToNextSlide() { + goToNextSlide(): void { this.imageSlides.swiperRef.slideNext(); } - goToPrevSlide() { + goToPrevSlide(): void { this.imageSlides.swiperRef.slidePrev(); } - getActiveIndex() { + getActiveIndex(): void { this.activeIndex = this.imageSlides.swiperRef.activeIndex; } - async deleteAttachment() { + async deleteAttachment(): Promise { const activeIndex = await this.imageSlides.swiperRef.activeIndex; try { this.trackingService.deleteFileClicked({ 'File ID': this.attachments[activeIndex].id }); @@ -113,37 +113,36 @@ export class FyViewAttachmentComponent implements OnInit { }); await deletePopover.present(); - const { data } = await deletePopover.onWillDismiss(); - - if (data && data.action) { - if (data.action === 'remove') { - from(this.loaderService.showLoader()) - .pipe( - switchMap(() => { - if (this.attachments[activeIndex].id) { - return this.fileService.delete(this.attachments[activeIndex].id); - } else { - return of(null); - } - }), - finalize(() => from(this.loaderService.hideLoader())) - ) - .subscribe(() => { - try { - this.trackingService.fileDeleted({ 'File ID': this.attachments[activeIndex].id }); - } catch (error) {} - this.attachments.splice(activeIndex, 1); - if (this.attachments.length === 0) { - this.modalController.dismiss({ attachments: this.attachments }); + const response: OverlayEventDetail<{ action: string }> = await deletePopover.onWillDismiss(); + const data = response.data; + + if (data?.action === 'remove') { + from(this.loaderService.showLoader()) + .pipe( + switchMap(() => { + if (this.attachments[activeIndex].id) { + return this.spenderFileService.deleteFilesBulk([this.attachments[activeIndex].id]); } else { - if (activeIndex > 0) { - this.goToPrevSlide(); - } else { - this.goToNextSlide(); - } + return of(null); } - }); - } + }), + finalize(() => from(this.loaderService.hideLoader())) + ) + .subscribe(() => { + try { + this.trackingService.fileDeleted({ 'File ID': this.attachments[activeIndex].id }); + } catch (error) {} + this.attachments.splice(activeIndex, 1); + if (this.attachments.length === 0) { + this.modalController.dismiss({ attachments: this.attachments }); + } else { + if (activeIndex > 0) { + this.goToPrevSlide(); + } else { + this.goToNextSlide(); + } + } + }); } } }