Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix / waiting for payment PPV/TVOD offers #541

Merged
merged 5 commits into from
Jun 7, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/common/src/controllers/AccountController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@ export default class AccountController {
let pendingOffer: Offer | null = null;

if (!activeSubscription && !!retry && retry > 0) {
const retryDelay = 1500; // Any initial delay has already occured, so we can set this to a fixed value
const retryDelay = 1500; // Any initial delay has already occurred, so we can set this to a fixed value

return await this.reloadSubscriptions({ delay: retryDelay, retry: retry - 1 });
}
Expand Down
13 changes: 9 additions & 4 deletions packages/common/src/controllers/CheckoutController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { useCheckoutStore } from '../stores/CheckoutStore';
import { useAccountStore } from '../stores/AccountStore';
import { FormValidationError } from '../errors/FormValidationError';
import { determineSwitchDirection } from '../utils/subscription';
import { logDev } from '../utils/common';

@injectable()
export default class CheckoutController {
Expand All @@ -52,10 +53,14 @@ export default class CheckoutController {
useCheckoutStore.setState({ subscriptionOffers });
}

if (!useCheckoutStore.getState().switchSubscriptionOffers.length) {
const subscriptionSwitches = await this.getSubscriptionSwitches();
const switchSubscriptionOffers = subscriptionSwitches ? await this.getOffers({ offerIds: subscriptionSwitches }) : [];
useCheckoutStore.setState({ switchSubscriptionOffers });
try {
if (!useCheckoutStore.getState().switchSubscriptionOffers.length) {
const subscriptionSwitches = await this.getSubscriptionSwitches();
AntonLantukh marked this conversation as resolved.
Show resolved Hide resolved
const switchSubscriptionOffers = subscriptionSwitches ? await this.getOffers({ offerIds: subscriptionSwitches }) : [];
useCheckoutStore.setState({ switchSubscriptionOffers });
}
} catch (error) {
logDev('Failed to get subscription switches', error);
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,38 @@ export default class JWPCheckoutService extends CheckoutService {
};
};

private formatOffer = (offer: AccessFee): Offer => {
/**
* Format a (Cleeng like) offer id for the given access fee (pricing option). For JWP, we need the asset id and
* access fee id in some cases.
*/
private formatOfferId(offer: AccessFee) {
const ppvOffers = ['ppv', 'ppv_custom'];
const offerId = ppvOffers.includes(offer.access_type.name) ? `C${offer.id}` : `S${offer.id}`;

return ppvOffers.includes(offer.access_type.name) ? `C${offer.item_id}_${offer.id}` : `S${offer.item_id}_${offer.id}`;
}

/**
* Parse the given offer id and extract the asset id.
* The offer id might be the Cleeng format (`S<assetId>_<pricingOptionId>`) or the asset id as string.
*/
private parseOfferId(offerId: string | number) {
if (typeof offerId === 'string') {
// offer id format `S<assetId>_<pricingOptionId>`
if (offerId.startsWith('C') || offerId.startsWith('S')) {
return parseInt(offerId.slice(1).split('_')[0]);
}

// offer id format `<assetId>`
return parseInt(offerId);
}

return offerId;
}

private formatOffer = (offer: AccessFee): Offer => {
return {
id: offer.id,
offerId,
offerId: this.formatOfferId(offer),
offerCurrency: offer.currency,
customerPriceInclTax: offer.amount,
customerCurrency: offer.currency,
Expand Down Expand Up @@ -97,9 +122,9 @@ export default class JWPCheckoutService extends CheckoutService {

getOffers: GetOffers = async (payload) => {
const offers = await Promise.all(
payload.offerIds.map(async (assetId) => {
payload.offerIds.map(async (offerId) => {
try {
const { data } = await InPlayer.Asset.getAssetAccessFees(parseInt(`${assetId}`));
const { data } = await InPlayer.Asset.getAssetAccessFees(this.parseOfferId(offerId));

return data?.map((offer) => this.formatOffer(offer));
} catch {
Expand Down Expand Up @@ -217,7 +242,7 @@ export default class JWPCheckoutService extends CheckoutService {

getEntitlements: GetEntitlements = async ({ offerId }) => {
try {
const response = await InPlayer.Asset.checkAccessForAsset(parseInt(offerId));
const response = await InPlayer.Asset.checkAccessForAsset(this.parseOfferId(offerId));
return this.formatEntitlements(response.data.expires_at, true);
} catch {
return this.formatEntitlements();
Expand Down
20 changes: 14 additions & 6 deletions packages/hooks-react/src/useCheckAccess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ type IntervalCheckAccessPayload = {
interval?: number;
iterations?: number;
offerId?: string;
callback?: (hasAccess: boolean) => void;
callback?: ({ hasAccess, offerId }: { hasAccess: boolean; offerId: string }) => void;
};

const useCheckAccess = () => {
Expand All @@ -23,20 +23,28 @@ const useCheckAccess = () => {

const intervalCheckAccess = useCallback(
({ interval = 3000, iterations = 5, offerId, callback }: IntervalCheckAccessPayload) => {
if (!offerId && offers?.[0]) {
offerId = offers[0];
if (!offerId) {
offerId = offers?.[0] || '';
}

if (!offerId) {
callback?.({ hasAccess: false, offerId: '' });
return;
ChristiaanScheermeijer marked this conversation as resolved.
Show resolved Hide resolved
}

intervalRef.current = window.setInterval(async () => {
const hasAccess = await accountController.checkEntitlements(offerId);

if (hasAccess) {
await accountController.reloadSubscriptions({ retry: 10, delay: 2000 });
callback?.(true);
window.clearInterval(intervalRef.current);
// No duplicate retry mechanism. This can also be a TVOD offer which isn't validated using the
// reloadSubscriptions method.
await accountController.reloadSubscriptions();
callback?.({ hasAccess: true, offerId: offerId || '' });
} else if (--iterations === 0) {
window.clearInterval(intervalRef.current);
setErrorMessage(t('payment.longer_than_usual'));
callback?.(false);
callback?.({ hasAccess: false, offerId: offerId || '' });
}
}, interval);
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,18 @@ const WaitingForPayment = () => {
interval: 3000,
iterations: 5,
offerId,
callback: (hasAccess) => {
callback: ({ hasAccess, offerId }) => {
if (!hasAccess) return;

announce(t('checkout.payment_success'), 'success');
navigate(modalURLFromLocation(location, 'welcome'));

// close the modal for PPV/TVOD offers
if (offerId.startsWith('C') || offerId.startsWith('P')) {
// should we show a dedicated modal for TVOD access?
royschut marked this conversation as resolved.
Show resolved Hide resolved
navigate(modalURLFromLocation(location, null));
} else {
navigate(modalURLFromLocation(location, 'welcome'));
}
},
});
//eslint-disable-next-line
Expand Down
33 changes: 4 additions & 29 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1879,7 +1879,7 @@
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6"
integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==

"@jridgewell/set-array@^1.2.1":
"@jridgewell/set-array@^1.0.1", "@jridgewell/set-array@^1.2.1":
version "1.2.1"
resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280"
integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==
Expand Down Expand Up @@ -9925,7 +9925,7 @@ [email protected]:
resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6"
integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==

"string-width-cjs@npm:string-width@^4.2.0":
"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
Expand All @@ -9942,15 +9942,6 @@ string-width@^2.1.0:
is-fullwidth-code-point "^2.0.0"
strip-ansi "^4.0.0"

string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
dependencies:
emoji-regex "^8.0.0"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"

string-width@^5.0.1, string-width@^5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794"
Expand Down Expand Up @@ -10048,7 +10039,7 @@ stringify-object@^3.3.0:
is-obj "^1.0.1"
is-regexp "^1.0.0"

"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
Expand All @@ -10069,13 +10060,6 @@ strip-ansi@^5.1.0:
dependencies:
ansi-regex "^4.1.0"

strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"

strip-ansi@^7.0.1, strip-ansi@^7.1.0:
version "7.1.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45"
Expand Down Expand Up @@ -11689,16 +11673,7 @@ [email protected]:
resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343"
integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==

"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
dependencies:
ansi-styles "^4.0.0"
string-width "^4.1.0"
strip-ansi "^6.0.0"

wrap-ansi@^7.0.0:
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
Expand Down
Loading