feat: iap (#1996)
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { WebApplication } from '@/Application/Application'
|
||||
import { PremiumFeatureModalType } from '@/Components/PremiumFeaturesModal/PremiumFeatureModalType'
|
||||
import { destroyAllObjectProperties } from '@/Utils'
|
||||
import {
|
||||
ApplicationEvent,
|
||||
@@ -16,6 +17,7 @@ export class FeaturesController extends AbstractViewController {
|
||||
hasSmartViews: boolean
|
||||
hasFiles: boolean
|
||||
premiumAlertFeatureName: string | undefined
|
||||
premiumAlertType: PremiumFeatureModalType | undefined = undefined
|
||||
|
||||
override deinit() {
|
||||
super.deinit()
|
||||
@@ -25,6 +27,7 @@ export class FeaturesController extends AbstractViewController {
|
||||
;(this.hasSmartViews as unknown) = undefined
|
||||
;(this.hasFiles as unknown) = undefined
|
||||
;(this.premiumAlertFeatureName as unknown) = undefined
|
||||
;(this.premiumAlertType as unknown) = undefined
|
||||
|
||||
destroyAllObjectProperties(this)
|
||||
}
|
||||
@@ -43,10 +46,11 @@ export class FeaturesController extends AbstractViewController {
|
||||
hasFolders: observable,
|
||||
hasSmartViews: observable,
|
||||
hasFiles: observable,
|
||||
|
||||
premiumAlertType: observable,
|
||||
premiumAlertFeatureName: observable,
|
||||
showPremiumAlert: action,
|
||||
closePremiumAlert: action,
|
||||
showPurchaseSuccessAlert: action,
|
||||
})
|
||||
|
||||
this.showPremiumAlert = this.showPremiumAlert.bind(this)
|
||||
@@ -55,6 +59,9 @@ export class FeaturesController extends AbstractViewController {
|
||||
this.disposers.push(
|
||||
application.addEventObserver(async (event) => {
|
||||
switch (event) {
|
||||
case ApplicationEvent.DidPurchaseSubscription:
|
||||
this.showPurchaseSuccessAlert()
|
||||
break
|
||||
case ApplicationEvent.FeaturesUpdated:
|
||||
case ApplicationEvent.Launched:
|
||||
runInAction(() => {
|
||||
@@ -76,11 +83,17 @@ export class FeaturesController extends AbstractViewController {
|
||||
|
||||
public async showPremiumAlert(featureName: string): Promise<void> {
|
||||
this.premiumAlertFeatureName = featureName
|
||||
return when(() => this.premiumAlertFeatureName === undefined)
|
||||
this.premiumAlertType = PremiumFeatureModalType.UpgradePrompt
|
||||
|
||||
return when(() => this.premiumAlertType === undefined)
|
||||
}
|
||||
|
||||
showPurchaseSuccessAlert = () => {
|
||||
this.premiumAlertType = PremiumFeatureModalType.UpgradeSuccess
|
||||
}
|
||||
|
||||
public closePremiumAlert() {
|
||||
this.premiumAlertFeatureName = undefined
|
||||
this.premiumAlertType = undefined
|
||||
}
|
||||
|
||||
private isEntitledToFiles(): boolean {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { LoggingDomain, log } from '@/Logging'
|
||||
import { loadPurchaseFlowUrl } from '@/Components/PurchaseFlow/PurchaseFlowFunctions'
|
||||
import { InternalEventBus } from '@standardnotes/snjs'
|
||||
import { InternalEventBus, AppleIAPProductId } from '@standardnotes/snjs'
|
||||
import { action, makeObservable, observable } from 'mobx'
|
||||
import { WebApplication } from '../../Application/Application'
|
||||
import { AbstractViewController } from '../Abstract/AbstractViewController'
|
||||
@@ -26,15 +27,67 @@ export class PurchaseFlowController extends AbstractViewController {
|
||||
this.currentPane = currentPane
|
||||
}
|
||||
|
||||
openPurchaseFlow = (): void => {
|
||||
openPurchaseFlow = (plan = AppleIAPProductId.ProPlanYearly): void => {
|
||||
const user = this.application.getUser()
|
||||
if (!user) {
|
||||
this.isOpen = true
|
||||
return
|
||||
}
|
||||
|
||||
if (this.application.isNativeIOS()) {
|
||||
void this.beginIosIapPurchaseFlow(plan)
|
||||
} else {
|
||||
loadPurchaseFlowUrl(this.application).catch(console.error)
|
||||
}
|
||||
}
|
||||
|
||||
openPurchaseWebpage = () => {
|
||||
loadPurchaseFlowUrl(this.application).catch((err) => {
|
||||
console.error(err)
|
||||
this.application.alertService.alert(err).catch(console.error)
|
||||
})
|
||||
}
|
||||
|
||||
beginIosIapPurchaseFlow = async (plan: AppleIAPProductId): Promise<void> => {
|
||||
const result = await this.application.mobileDevice().purchaseSubscriptionIAP(plan)
|
||||
|
||||
log(LoggingDomain.Purchasing, 'BeginIosIapPurchaseFlow result', result)
|
||||
|
||||
if (!result) {
|
||||
void this.application.alertService.alert('Your purchase was canceled or failed. Please try again.')
|
||||
return
|
||||
}
|
||||
|
||||
const showGenericError = () => {
|
||||
void this.application.alertService.alert(
|
||||
'There was an error confirming your purchase. Please contact support at help@standardnotes.com.',
|
||||
)
|
||||
}
|
||||
|
||||
log(LoggingDomain.Purchasing, 'Confirming result with our server')
|
||||
|
||||
const token = await this.application.getNewSubscriptionToken()
|
||||
|
||||
if (!token) {
|
||||
log(LoggingDomain.Purchasing, 'Unable to generate subscription token')
|
||||
showGenericError()
|
||||
return
|
||||
}
|
||||
|
||||
const confirmResult = await this.application.subscriptions.confirmAppleIAP(result, token)
|
||||
|
||||
log(LoggingDomain.Purchasing, 'Server confirm result', confirmResult)
|
||||
|
||||
if (confirmResult) {
|
||||
void this.application.alerts.alert(
|
||||
'Please allow a few minutes for your subscription benefits to activate. You will see a confirmation alert in the app when your subscription is ready.',
|
||||
'Your purchase was successful!',
|
||||
)
|
||||
} else {
|
||||
showGenericError()
|
||||
}
|
||||
}
|
||||
|
||||
closePurchaseFlow = (): void => {
|
||||
this.isOpen = false
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ export class SubscriptionController extends AbstractViewController {
|
||||
userSubscription: Subscription | undefined = undefined
|
||||
availableSubscriptions: AvailableSubscriptions | undefined = undefined
|
||||
subscriptionInvitations: Invitation[] | undefined = undefined
|
||||
hideSubscriptionMarketing: boolean
|
||||
hasAccount: boolean
|
||||
|
||||
override deinit() {
|
||||
@@ -39,14 +38,12 @@ export class SubscriptionController extends AbstractViewController {
|
||||
private subscriptionManager: SubscriptionClientInterface,
|
||||
) {
|
||||
super(application, eventBus)
|
||||
this.hideSubscriptionMarketing = application.hideSubscriptionMarketing
|
||||
this.hasAccount = application.hasAccount()
|
||||
|
||||
makeObservable(this, {
|
||||
userSubscription: observable,
|
||||
availableSubscriptions: observable,
|
||||
subscriptionInvitations: observable,
|
||||
hideSubscriptionMarketing: observable,
|
||||
hasAccount: observable,
|
||||
|
||||
userSubscriptionName: computed,
|
||||
|
||||
Reference in New Issue
Block a user