Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
4 changes: 4 additions & 0 deletions packages/subscription-controller/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Added `lastSubscription` in state returned from `getSubscriptions` method ([#7110](https://github.com/MetaMask/core/pull/7110))

## [3.3.0]

### Changed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ const MOCK_SUBSCRIPTION: Subscription = {
last4: '1234',
},
},
isEligibleForSupport: true,
};

const MOCK_PRODUCT_PRICE: ProductPricing = {
Expand Down Expand Up @@ -545,6 +546,30 @@ describe('SubscriptionController', () => {
},
);
});

it('should update state when lastSubscription changes from undefined to defined', async () => {
await withController(
{
state: {
lastSubscription: undefined,
},
},
async ({ controller, mockService }) => {
mockService.getSubscriptions.mockResolvedValue({
customerId: 'cus_1',
subscriptions: [],
trialedProducts: [],
lastSubscription: MOCK_SUBSCRIPTION,
});

await controller.getSubscriptions();

expect(controller.state.lastSubscription).toStrictEqual(
MOCK_SUBSCRIPTION,
);
},
);
});
});

describe('getSubscriptionByProduct', () => {
Expand Down Expand Up @@ -1251,7 +1276,6 @@ describe('SubscriptionController', () => {
),
).toMatchInlineSnapshot(`
Object {
"subscriptions": Array [],
"trialedProducts": Array [],
}
`);
Expand Down
40 changes: 34 additions & 6 deletions packages/subscription-controller/src/SubscriptionController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ export type SubscriptionControllerState = {
trialedProducts: ProductType[];
subscriptions: Subscription[];
pricing?: PricingResponse;

/** The last subscription that user has subscribed to if any. */
lastSubscription?: Subscription;
/**
* The last selected payment method for the user.
* This is used to display the last selected payment method in the UI.
Expand Down Expand Up @@ -194,7 +195,13 @@ export function getDefaultSubscriptionControllerState(): SubscriptionControllerS
const subscriptionControllerMetadata: StateMetadata<SubscriptionControllerState> =
{
subscriptions: {
includeInStateLogs: true,
includeInStateLogs: false,
persist: true,
includeInDebugSnapshot: false,
usedInUi: true,
},
lastSubscription: {
includeInStateLogs: false,
persist: true,
includeInDebugSnapshot: false,
usedInUi: true,
Expand Down Expand Up @@ -342,10 +349,12 @@ export class SubscriptionController extends StaticIntervalPollingController()<
const currentSubscriptions = this.state.subscriptions;
const currentTrialedProducts = this.state.trialedProducts;
const currentCustomerId = this.state.customerId;
const currentLastSubscription = this.state.lastSubscription;
const {
customerId: newCustomerId,
subscriptions: newSubscriptions,
trialedProducts: newTrialedProducts,
lastSubscription: newLastSubscription,
} = await this.#subscriptionService.getSubscriptions();

// check if the new subscriptions are different from the current subscriptions
Expand All @@ -358,20 +367,27 @@ export class SubscriptionController extends StaticIntervalPollingController()<
currentTrialedProducts,
newTrialedProducts,
);
// check if the new last subscription is different from the current last subscription
const isLastSubscriptionEqual = this.#isSubscriptionEqual(
currentLastSubscription,
newLastSubscription,
);

const areCustomerIdsEqual = currentCustomerId === newCustomerId;

// only update the state if the subscriptions or trialed products are different
// this prevents unnecessary state updates events, easier for the clients to handle
if (
!areSubscriptionsEqual ||
!isLastSubscriptionEqual ||
!areTrialedProductsEqual ||
!areCustomerIdsEqual
) {
this.update((state) => {
state.subscriptions = newSubscriptions;
state.customerId = newCustomerId;
state.trialedProducts = newTrialedProducts;
state.lastSubscription = newLastSubscription;
});
this.#shouldCallRefreshAuthToken = true;
}
Expand Down Expand Up @@ -891,13 +907,25 @@ export class SubscriptionController extends StaticIntervalPollingController()<
// Check if all subscriptions are equal
return sortedOldSubs.every((oldSub, index) => {
const newSub = sortedNewSubs[index];
return (
this.#stringifySubscription(oldSub) ===
this.#stringifySubscription(newSub)
);
return this.#isSubscriptionEqual(oldSub, newSub);
});
}

#isSubscriptionEqual(oldSub?: Subscription, newSub?: Subscription): boolean {
// not equal if one is undefined and the other is defined
if (!oldSub || !newSub) {
if (!oldSub && !newSub) {
return true;
}
return false;
}

return (
this.#stringifySubscription(oldSub) ===
this.#stringifySubscription(newSub)
);
}

#stringifySubscription(subscription: Subscription): string {
const subsWithSortedProducts = {
...subscription,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ const MOCK_SUBSCRIPTION: Subscription = {
last4: '1234',
},
},
isEligibleForSupport: true,
};

const MOCK_ACCESS_TOKEN = 'mock-access-token-12345';
Expand Down
8 changes: 8 additions & 0 deletions packages/subscription-controller/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ export type Subscription = {
trialEnd?: string; // ISO 8601
/** Crypto payment only: next billing cycle date (e.g after 12 months) */
endDate?: string; // ISO 8601
/** The date the subscription was canceled. */
canceledAt?: string; // ISO 8601
/** The date the subscription was marked as inactive (paused/past_due/canceled). */
inactiveAt?: string; // ISO 8601
/** Whether the user is eligible for support features (priority support and filing claims). True for active subscriptions and inactive subscriptions within grace period. */
isEligibleForSupport: boolean;
billingCycles?: number;
};

Expand Down Expand Up @@ -110,6 +116,8 @@ export type GetSubscriptionsResponse = {
customerId?: string;
subscriptions: Subscription[];
trialedProducts: ProductType[];
/** The last subscription that user has subscribed to if any. */
lastSubscription?: Subscription;
};

export type StartSubscriptionRequest = {
Expand Down
Loading