diff --git a/android/app/capacitor.build.gradle b/android/app/capacitor.build.gradle index 8c2576eae..6b66551e2 100644 --- a/android/app/capacitor.build.gradle +++ b/android/app/capacitor.build.gradle @@ -33,7 +33,7 @@ dependencies { implementation project(':appsflyer-capacitor-plugin') implementation project(':capacitor-blob-writer') implementation project(':capacitor-native-settings') - implementation "com.android.billingclient:billing:4.0.0" + implementation "com.android.billingclient:billing:5.2.1" } diff --git a/package-lock.json b/package-lock.json index 5979d24e5..6407fee1d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,6 @@ "@angular/platform-browser-dynamic": "^14.2.0", "@angular/router": "^14.2.0", "@awesome-cordova-plugins/core": "^5.46.0", - "@awesome-cordova-plugins/in-app-purchase-2": "^5.43.0", "@capacitor-community/advertising-id": "^5.0.0", "@capacitor-community/bluetooth-le": "^2.2.3", "@capacitor-community/http": "github:numbersprotocol/http#fix-catch-disabled-Local-Network-case-on-iOS", @@ -63,7 +62,7 @@ "capacitor-blob-writer": "^1.0.4", "capacitor-native-settings": "^4.0.3", "compressorjs": "^1.0.7", - "cordova-plugin-purchase": "^11.0.0", + "cordova-plugin-purchase": "^13.9.0", "ethers": "^6.8.1", "hammerjs": "^2.0.8", "immutable": "^4.0.0-rc.14", @@ -1431,18 +1430,6 @@ "rxjs": "^5.5.0 || ^6.5.0 || ^7.3.0" } }, - "node_modules/@awesome-cordova-plugins/in-app-purchase-2": { - "version": "5.43.0", - "resolved": "https://registry.npmjs.org/@awesome-cordova-plugins/in-app-purchase-2/-/in-app-purchase-2-5.43.0.tgz", - "integrity": "sha512-y292xt+DSqsIpFCe0X7yjTZkC4moPT+gYpo7C59yBR8OeZPx0LHNTth3rzeSYsVityyCjnpEIf08x0hGfKr3bw==", - "dependencies": { - "@types/cordova": "latest" - }, - "peerDependencies": { - "@awesome-cordova-plugins/core": "^5.1.0", - "rxjs": "^5.5.0 || ^6.5.0 || ^7.3.0" - } - }, "node_modules/@babel/code-frame": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", @@ -8414,9 +8401,9 @@ } }, "node_modules/cordova-plugin-purchase": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/cordova-plugin-purchase/-/cordova-plugin-purchase-11.0.0.tgz", - "integrity": "sha512-FkgOyWBYS989dYpM6d3R36VrdsHweTbmp5y7ELa1GwMYq2AG+ImdB6DJcVpyU/se/zpTndBWH/zN9s3AFKfsLg==" + "version": "13.9.0", + "resolved": "https://registry.npmjs.org/cordova-plugin-purchase/-/cordova-plugin-purchase-13.9.0.tgz", + "integrity": "sha512-dzN81dlfxYMidhPQRjpo8dNeQO7Fifwsf2fsi6AWMT+aiPBf5MVtwbzRBMiSuHJnMHCuNY9oIml37zrIXwbI/w==" }, "node_modules/core-js-compat": { "version": "3.25.0", @@ -25065,14 +25052,6 @@ "@types/cordova": "latest" } }, - "@awesome-cordova-plugins/in-app-purchase-2": { - "version": "5.43.0", - "resolved": "https://registry.npmjs.org/@awesome-cordova-plugins/in-app-purchase-2/-/in-app-purchase-2-5.43.0.tgz", - "integrity": "sha512-y292xt+DSqsIpFCe0X7yjTZkC4moPT+gYpo7C59yBR8OeZPx0LHNTth3rzeSYsVityyCjnpEIf08x0hGfKr3bw==", - "requires": { - "@types/cordova": "latest" - } - }, "@babel/code-frame": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", @@ -30177,9 +30156,9 @@ } }, "cordova-plugin-purchase": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/cordova-plugin-purchase/-/cordova-plugin-purchase-11.0.0.tgz", - "integrity": "sha512-FkgOyWBYS989dYpM6d3R36VrdsHweTbmp5y7ELa1GwMYq2AG+ImdB6DJcVpyU/se/zpTndBWH/zN9s3AFKfsLg==" + "version": "13.9.0", + "resolved": "https://registry.npmjs.org/cordova-plugin-purchase/-/cordova-plugin-purchase-13.9.0.tgz", + "integrity": "sha512-dzN81dlfxYMidhPQRjpo8dNeQO7Fifwsf2fsi6AWMT+aiPBf5MVtwbzRBMiSuHJnMHCuNY9oIml37zrIXwbI/w==" }, "core-js-compat": { "version": "3.25.0", diff --git a/package.json b/package.json index 0fb03c52c..b4210371b 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,6 @@ "@angular/platform-browser-dynamic": "^14.2.0", "@angular/router": "^14.2.0", "@awesome-cordova-plugins/core": "^5.46.0", - "@awesome-cordova-plugins/in-app-purchase-2": "^5.43.0", "@capacitor-community/advertising-id": "^5.0.0", "@capacitor-community/bluetooth-le": "^2.2.3", "@capacitor-community/http": "github:numbersprotocol/http#fix-catch-disabled-Local-Network-case-on-iOS", @@ -74,7 +73,7 @@ "capacitor-blob-writer": "^1.0.4", "capacitor-native-settings": "^4.0.3", "compressorjs": "^1.0.7", - "cordova-plugin-purchase": "^11.0.0", + "cordova-plugin-purchase": "^13.9.0", "ethers": "^6.8.1", "hammerjs": "^2.0.8", "immutable": "^4.0.0-rc.14", diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts index d535634eb..4d3c14ca8 100644 --- a/src/app/app.component.spec.ts +++ b/src/app/app.component.spec.ts @@ -1,7 +1,6 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { TestBed, waitForAsync } from '@angular/core/testing'; -import { InAppPurchase2 } from '@awesome-cordova-plugins/in-app-purchase-2/ngx'; import { Platform } from '@ionic/angular'; import { AppComponent } from './app.component'; import { CapacitorPluginsTestingModule } from './shared/capacitor-plugins/capacitor-plugins-testing.module'; @@ -22,12 +21,6 @@ describe('AppComponent', () => { is: platformIsSpy, }); - const iap2SpyMethods = ['error', 'ready', 'when', 'refresh', 'off']; - const inAppPurchase2Spy = jasmine.createSpyObj( - 'InAppPurchase2', - iap2SpyMethods - ); - TestBed.configureTestingModule({ declarations: [AppComponent], schemas: [CUSTOM_ELEMENTS_SCHEMA], @@ -37,10 +30,7 @@ describe('AppComponent', () => { getTranslocoTestingModule(), MaterialTestingModule, ], - providers: [ - { provide: Platform, useValue: platformSpy }, - { provide: InAppPurchase2, useValue: inAppPurchase2Spy }, - ], + providers: [{ provide: Platform, useValue: platformSpy }], }).compileComponents(); }) ); diff --git a/src/app/app.module.ts b/src/app/app.module.ts index ea69db6d5..ed941933e 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -3,7 +3,6 @@ import { MAT_SNACK_BAR_DEFAULT_OPTIONS } from '@angular/material/snack-bar'; import { BrowserModule, HammerModule } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { RouteReuseStrategy } from '@angular/router'; -import { InAppPurchase2 } from '@awesome-cordova-plugins/in-app-purchase-2/ngx'; import { IonicModule, IonicRouteStrategy } from '@ionic/angular'; import { FormlyModule } from '@ngx-formly/core'; import { FormlyMaterialModule } from '@ngx-formly/material'; @@ -36,7 +35,6 @@ import { SharedModule } from './shared/shared.module'; provide: MAT_SNACK_BAR_DEFAULT_OPTIONS, useValue: { duration: 2500 }, }, - InAppPurchase2, ], bootstrap: [AppComponent], }) diff --git a/src/app/features/wallets/buy-num/buy-num.page.html b/src/app/features/wallets/buy-num/buy-num.page.html index 2c7a832a9..9ef6dc1ea 100644 --- a/src/app/features/wallets/buy-num/buy-num.page.html +++ b/src/app/features/wallets/buy-num/buy-num.page.html @@ -25,7 +25,7 @@ >
- {{ product.inAppProduct.price }} + {{ product.inAppProduct.pricing?.price }}
@@ -38,9 +38,6 @@ {{ t('wallets.buyCredits.buyXCredits', { credits: product.numPoints }) }} - diff --git a/src/app/features/wallets/buy-num/buy-num.page.spec.ts b/src/app/features/wallets/buy-num/buy-num.page.spec.ts index a55dc6b13..9429bd718 100644 --- a/src/app/features/wallets/buy-num/buy-num.page.spec.ts +++ b/src/app/features/wallets/buy-num/buy-num.page.spec.ts @@ -1,5 +1,4 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { InAppPurchase2 } from '@awesome-cordova-plugins/in-app-purchase-2/ngx'; import { SharedTestingModule } from '../../../shared/shared-testing.module'; import { BuyNumPage } from './buy-num.page'; @@ -10,16 +9,9 @@ describe('BuyNumPage', () => { beforeEach( waitForAsync(() => { - const iap2SpyMethods = ['error', 'ready', 'when', 'refresh', 'off']; - const inAppPurchase2Spy = jasmine.createSpyObj( - 'InAppPurchase2', - iap2SpyMethods - ); - TestBed.configureTestingModule({ declarations: [BuyNumPage], imports: [SharedTestingModule], - providers: [{ provide: InAppPurchase2, useValue: inAppPurchase2Spy }], }).compileComponents(); fixture = TestBed.createComponent(BuyNumPage); diff --git a/src/app/features/wallets/buy-num/buy-num.page.ts b/src/app/features/wallets/buy-num/buy-num.page.ts index 8eaae3e31..800e0a896 100644 --- a/src/app/features/wallets/buy-num/buy-num.page.ts +++ b/src/app/features/wallets/buy-num/buy-num.page.ts @@ -1,11 +1,13 @@ import { ChangeDetectorRef, Component, OnInit } from '@angular/core'; -import { IAPProduct } from '@awesome-cordova-plugins/in-app-purchase-2/ngx'; import { AlertController } from '@ionic/angular'; import { TranslocoService } from '@ngneat/transloco'; +import { UntilDestroy } from '@ngneat/until-destroy'; import { combineLatest } from 'rxjs'; -import { map, tap } from 'rxjs/operators'; +import { filter, first, map, tap } from 'rxjs/operators'; +import { BlockingActionService } from '../../../shared/blocking-action/blocking-action.service'; import { InAppStoreService } from '../../../shared/in-app-store/in-app-store.service'; +@UntilDestroy() @Component({ selector: 'app-buy-num', templateUrl: './buy-num.page.html', @@ -34,21 +36,33 @@ export class BuyNumPage implements OnInit { tap(_ => this.ref.detectChanges()) ); + readonly isProcessingOrder$ = this.store.isProcessingOrder$; + constructor( private readonly store: InAppStoreService, private readonly ref: ChangeDetectorRef, private readonly alertController: AlertController, - private readonly translocoService: TranslocoService + private readonly translocoService: TranslocoService, + private readonly blockingActionService: BlockingActionService ) {} ngOnInit() { this.store.refreshNumPointsPricing(); } - purchase(product: IAPProduct) { + purchase(product: CdvPurchase.Product) { + this.showLoadingIndicatorUntillOrderIsProcessed(); this.store.purchase(product); } + private showLoadingIndicatorUntillOrderIsProcessed() { + const action$ = this.isProcessingOrder$.pipe( + filter(isProcessing => isProcessing === false), + first() + ); + this.blockingActionService.run$(action$).subscribe(); + } + async showNumPointsQuantity(numPoints: number) { const info = this.translocoService.translate( 'wallets.buyCredits.thisPackageIncludeXCredits', diff --git a/src/app/shared/in-app-store/in-app-store.service.spec.ts b/src/app/shared/in-app-store/in-app-store.service.spec.ts index 37e304a94..f479b7174 100644 --- a/src/app/shared/in-app-store/in-app-store.service.spec.ts +++ b/src/app/shared/in-app-store/in-app-store.service.spec.ts @@ -1,5 +1,4 @@ import { TestBed } from '@angular/core/testing'; -import { InAppPurchase2 } from '@awesome-cordova-plugins/in-app-purchase-2/ngx'; import { SharedModule } from '../shared.module'; import { InAppStoreService } from './in-app-store.service'; @@ -10,7 +9,6 @@ describe('InAppStoreService', () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [SharedModule], - providers: [InAppPurchase2], }); service = TestBed.inject(InAppStoreService); }); diff --git a/src/app/shared/in-app-store/in-app-store.service.ts b/src/app/shared/in-app-store/in-app-store.service.ts index f8e33b64d..71ae412b3 100644 --- a/src/app/shared/in-app-store/in-app-store.service.ts +++ b/src/app/shared/in-app-store/in-app-store.service.ts @@ -1,11 +1,8 @@ +import { HttpErrorResponse } from '@angular/common/http'; import { Injectable, OnDestroy } from '@angular/core'; -import { - IAPError, - IAPProduct, - InAppPurchase2, -} from '@awesome-cordova-plugins/in-app-purchase-2/ngx'; import { Platform, ToastController } from '@ionic/angular'; import { TranslocoService } from '@ngneat/transloco'; +import 'cordova-plugin-purchase'; import { BehaviorSubject, combineLatest } from 'rxjs'; import { map } from 'rxjs/operators'; import { @@ -24,9 +21,11 @@ import { ErrorService } from '../error/error.service'; export class InAppStoreService implements OnDestroy { debugPrint = setupInAppPurchaseDebugPrint('InAppStoreService'); - readonly inAppProducts$ = new BehaviorSubject([]); + readonly inAppProducts$ = new BehaviorSubject([]); readonly numPointPricesById$ = new BehaviorSubject({}); + private store!: CdvPurchase.Store; + readonly inAppProductsWithNumpoints$ = combineLatest([ this.inAppProducts$, this.numPointPricesById$, @@ -34,7 +33,7 @@ export class InAppStoreService implements OnDestroy { map(([inAppProducts, numPointPricesById]) => { return inAppProducts.map(inAppProduct => { const numPoints = this.numPointsForProduct( - inAppProduct, + inAppProduct.id, numPointPricesById ); return { inAppProduct, numPoints }; @@ -42,10 +41,11 @@ export class InAppStoreService implements OnDestroy { }) ); + readonly isProcessingOrder$ = new BehaviorSubject(false); + private readonly appId = 'io.numbersprotocol.capturelite'; constructor( - private readonly store: InAppPurchase2, private readonly platform: Platform, private readonly errorService: ErrorService, private readonly toastController: ToastController, @@ -63,11 +63,10 @@ export class InAppStoreService implements OnDestroy { try { await this.platform.ready(); - + this.store = CdvPurchase.store; this.regiseterStoreListeners(); this.registerStoreProducts(); - - this.store.refresh(); + this.store.initialize(); } catch (error) { const errorMessage = this.translocoService.translate( 'inAppPurchase.failedToInitInAppStore' @@ -98,30 +97,40 @@ export class InAppStoreService implements OnDestroy { } } - purchase(product: IAPProduct) { - this.store.order(product); + purchase(product: CdvPurchase.Product) { + const offer = product.getOffer(); + if (!offer) return; + this.isProcessingOrder$.next(true); + this.store.order(offer); } - private async finishPurchase(inAppProduct: IAPProduct) { - const pointsToAdd = this.numPointsForProduct( - inAppProduct, - this.numPointPricesById$.value - ); - - let receipt; - if (inAppProduct.transaction?.type === 'ios-appstore') { - receipt = inAppProduct.transaction.appStoreReceipt; + private async finishPurchase(receipt: CdvPurchase.VerifiedReceipt) { + const product = this.extractProductFromReceipt(receipt); + if (!product) { + receipt.finish(); + this.isProcessingOrder$.next(false); + return; } - if (inAppProduct.transaction?.type === 'android-playstore') { - receipt = inAppProduct.transaction.receipt; + + const storeReceipt = this.extractStoreReceipt(receipt); + if (!storeReceipt) { + receipt.finish(); + this.isProcessingOrder$.next(false); + return; } - if (!receipt) return; try { + const pointsToAdd = this.numPointsForProduct( + product.id, + this.numPointPricesById$.value + ); + await this.diaBackendNumService - .purchaseNumPoints$(pointsToAdd, receipt) + .purchaseNumPoints$(pointsToAdd, storeReceipt) .toPromise(); - inAppProduct.finish(); + + receipt.finish(); + this.isProcessingOrder$.next(false); this.notifyUser( this.translocoService.translate('wallets.buyCredits.xCreditsAdded', { @@ -129,10 +138,63 @@ export class InAppStoreService implements OnDestroy { }) ); } catch (error) { - const errorMessage = this.translocoService.translate( - 'wallets.buyCredits.failedToAddCredits' - ); - this.errorService.toastError$(errorMessage).toPromise(); + if ( + error instanceof HttpErrorResponse && + error.error.error?.type === 'duplicate_receipt_id' + ) { + /** + * The receipt has already been used to get NUM points. + * + * In case of duplicate receipt id, the user has already received the points + * and we can ignore the error. Duplicate receipt can happen if callbacks + * registered in CdvPurchase is called twice. Issue is more related to plugin itslef: + * https://github.com/j3k0/cordova-plugin-purchase/issues/1458 + * + * Thanks to our backend implementation, the user will not be given NUMs twice. + * In this case we just finish the receipt and make sure loading indicator is hidden. + */ + receipt.finish(); + this.isProcessingOrder$.next(false); + } else { + this.errorService + .toastError$( + this.translocoService.translate( + 'wallets.buyCredits.failedToAddCredits' + ) + ) + .toPromise(); + } + } + } + + // eslint-disable-next-line class-methods-use-this + private extractProductFromReceipt(receipt: CdvPurchase.VerifiedReceipt) { + for (const transaction of receipt.sourceReceipt.transactions) { + for (const product of transaction.products) { + const isIncluded = Object.values( + CaptureInAppProductIds + ).includes(product.id); + if (isIncluded) return product; + } + } + return null; + } + + // eslint-disable-next-line class-methods-use-this + private extractStoreReceipt( + receipt: CdvPurchase.VerifiedReceipt + ): string | undefined { + const platform = receipt.sourceReceipt.platform; + + if (platform === CdvPurchase.Platform.APPLE_APPSTORE) { + // nativeData is not documented, but it is there (can be veified by console.log(receipt)) + return (receipt.sourceReceipt as any).nativeData.appStoreReceipt; + } + + if (platform === CdvPurchase.Platform.GOOGLE_PLAY) { + // nativePurchase is not documented, but it is there (can be veified by console.log(receipt)) + return (receipt.sourceReceipt.transactions[0] as any).nativePurchase + .receipt; } } @@ -145,9 +207,9 @@ export class InAppStoreService implements OnDestroy { private regiseterStoreListeners() { this.store.error(this.onStoreError); this.store.ready(this.onStoreReady); - this.store.when('product').approved(this.onStoreProductApproved); - this.store.when('product').updated(this.onStoreProductUpdated); - this.store.when('product').verified(this.onStoreProductVerified); + this.store.when().approved(this.onStoreProductApproved); + this.store.when().productUpdated(this.onStoreProductUpdated); + this.store.when().verified(this.onStoreProductVerified); } private unregisterStoreListeners() { @@ -159,78 +221,64 @@ export class InAppStoreService implements OnDestroy { } private registerStoreProducts() { - const consumableProductIds = [ - CaptureInAppProductIds.BRONZE_PACK, - CaptureInAppProductIds.SLIVER_PACK, - CaptureInAppProductIds.GOLD_PACK, - CaptureInAppProductIds.PLATINUM_PACK, - ]; - const type = this.store.CONSUMABLE; + const consumableProductIds = Object.values(CaptureInAppProductIds); + const type = CdvPurchase.ProductType.CONSUMABLE; + const appstorePlatform = CdvPurchase.Platform.APPLE_APPSTORE; + const googlePlayPlatform = CdvPurchase.Platform.GOOGLE_PLAY; + const productsToRegister: CdvPurchase.IRegisterProduct[] = []; for (const id of consumableProductIds) { - this.store.register({ id, type }); + productsToRegister.push({ id, type, platform: appstorePlatform }); + productsToRegister.push({ id, type, platform: googlePlayPlatform }); } + + this.store.register(productsToRegister); } - private readonly onStoreError = (_: IAPError) => { + private readonly onStoreError = (error: CdvPurchase.IError) => { + this.isProcessingOrder$.next(false); + + if (error.message === 'The user cancelled the order.') return; + const errorMessage = this.translocoService.translate( 'inAppPurchase.inAppPurchaseErrorOcurred' ); this.errorService.toastError$(errorMessage).toPromise(); + // TODO: report to remote error service }; private readonly onStoreReady = () => { - const inAppProducts = this.store.products.filter( - product => this.shouldIgnoreProduct(product) === false - ); - this.inAppProducts$.next(inAppProducts); + this.inAppProducts$.next(this.store.products); }; - private readonly onStoreProductUpdated = (updatedProduct: IAPProduct) => { - if (this.shouldIgnoreProduct(updatedProduct)) { - return; - } - + private readonly onStoreProductUpdated = ( + updatedProduct: CdvPurchase.Product + ) => { this.debugPrint('onStoreProductUpdated', updatedProduct); - - const inAppProducts = this.inAppProducts$.value.map(product => - product.id === updatedProduct.id ? updatedProduct : product - ); - - this.inAppProducts$.next(inAppProducts); + this.inAppProducts$.next(this.store.products); }; - private readonly onStoreProductApproved = (product: IAPProduct) => { - if (this.shouldIgnoreProduct(product)) { - return; - } - this.debugPrint('onStoreProductApproved', product); - // TODO: in the future add validation logic here - product.verify(); + private readonly onStoreProductApproved = ( + transacction: CdvPurchase.Transaction + ) => { + this.debugPrint('onStoreProductApproved', transacction); + transacction.verify(); }; - private readonly onStoreProductVerified = (product: IAPProduct) => { - if (this.shouldIgnoreProduct(product)) { - return; - } - this.debugPrint('onStoreProductVerified', product); - this.finishPurchase(product); + private readonly onStoreProductVerified = ( + receipt: CdvPurchase.VerifiedReceipt + ) => { + this.debugPrint('onStoreProductVerified', receipt); + this.finishPurchase(receipt); }; - private shouldIgnoreProduct(product: IAPProduct) { - // For some reason on iOS there will be 1 in app product - // with product.id === io.numbersprotocol.capturelite - // we should ignore that product - return product.id === this.appId; - } - // eslint-disable-next-line class-methods-use-this private numPointsForProduct( - product: IAPProduct, + productId: string, numPriceListById: NumPointPricesById ) { - if (product.id in numPriceListById) { - return numPriceListById[product.id].quantitiy; + if (productId in numPriceListById) { + return numPriceListById[productId].quantitiy; } return 0; } @@ -248,7 +296,7 @@ export enum CaptureInAppProductIds { } interface InAppProductsWithNumPoint { - inAppProduct: IAPProduct; + inAppProduct: CdvPurchase.Product; numPoints: number; } diff --git a/src/app/utils/in-app-purchase.ts b/src/app/utils/in-app-purchase.ts index 38b0539d0..de74a70a2 100644 --- a/src/app/utils/in-app-purchase.ts +++ b/src/app/utils/in-app-purchase.ts @@ -1,5 +1,4 @@ import { isDevMode } from '@angular/core'; -import { IAPProduct } from '@awesome-cordova-plugins/in-app-purchase-2/ngx'; import { CaptureInAppProductIds } from '../shared/in-app-store/in-app-store.service'; export function truncateReceipt(recipt: string) { @@ -32,72 +31,66 @@ export function setupInAppPurchaseDebugPrint(tag: string) { * does not work in Web environment therefore we can use this util function * to pupulate with mock product to develop UI with different product states */ -export function generateMockInAppProducts(): IAPProduct[] { - const mockInAppProductSample: IAPProduct = { +export function generateMockInAppProducts(): CdvPurchase.Product[] { + const mockInAppProductSample: CdvPurchase.Product = { id: 'string', - alias: 'string', - type: 'string', - state: 'string', + className: 'Product', + platform: CdvPurchase.Platform.TEST, + offers: [], + pricing: undefined, + type: CdvPurchase.ProductType.CONSUMABLE, title: 'string', description: 'string', - priceMicros: 0, - price: 'string', - currency: 'string', - loaded: true, - valid: true, canPurchase: true, owned: true, - finish: () => ({}), - verify: () => ({}), - set: (_: string, __: any) => ({}), - stateChanged: () => ({}), - on: (_: string, __: any) => ({}), - once: (_: string, __: any) => ({}), - off: (_: any) => ({}), - trigger: (_: string, __: any) => ({}), + getOffer: () => undefined, + addOffer: () => ({} as CdvPurchase.Product), }; return [ { ...mockInAppProductSample, id: CaptureInAppProductIds.BRONZE_PACK, - title: 'Bronze Pack', - price: '0.99', - currency: 'USD', + title: '100 NumPoints', + description: '100 NumPoints', + pricing: undefined, canPurchase: true, - state: 'valid', - type: 'CONSUMABLE', + owned: true, + getOffer: () => undefined, + addOffer: () => ({} as CdvPurchase.Product), }, { ...mockInAppProductSample, - id: CaptureInAppProductIds.SLIVER_PACK, - title: 'Silver Pack', - price: '1.99', - state: 'valid', - canPurchase: false, - currency: 'USD', - type: 'CONSUMABLE', + title: '500 NumPoints', + description: '500 NumPoints', + pricing: undefined, + canPurchase: true, + owned: true, + getOffer: () => undefined, + addOffer: () => ({} as CdvPurchase.Product), }, { ...mockInAppProductSample, id: CaptureInAppProductIds.GOLD_PACK, - title: 'Gold Pack', - price: '2.99', - state: 'valid', - currency: 'USD', - type: 'CONSUMABLE', + title: '1000 NumPoints', + description: '1000 NumPoints', + pricing: undefined, canPurchase: true, + owned: true, + getOffer: () => undefined, + addOffer: () => ({} as CdvPurchase.Product), }, { ...mockInAppProductSample, id: CaptureInAppProductIds.PLATINUM_PACK, - title: 'Platinum Pack', - price: '3.99', - state: 'valid', - currency: 'USD', - type: 'CONSUMABLE', + title: '5000 NumPoints', + description: '5000 NumPoints', + pricing: undefined, canPurchase: true, + owned: true, + getOffer: () => undefined, + addOffer: () => ({} as CdvPurchase.Product), }, ]; }