Skip to content

Commit

Permalink
fix: display those with no subscription as Free Tier users (#2221)
Browse files Browse the repository at this point in the history
Closes #2218 

Users without a subscription will no longer be treated as early
adopters, but as Free tier users.
  • Loading branch information
e-schneid committed Feb 23, 2023
1 parent 3befe79 commit 81081bd
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 108 deletions.
Expand Up @@ -33,23 +33,18 @@ const StorageManager = ({ className = '', content }) => {
const uploaded = useMemo(() => data?.usedStorage?.uploaded || 0, [data]);
const psaPinned = useMemo(() => data?.usedStorage?.psaPinned || 0, [data]);
const limit = useMemo(() => {
if (currentPlan?.id === 'earlyAdopter') {
return data?.storageLimitBytes || defaultStorageLimit;
} else {
const byteConversion = currentPlan?.tiers?.[0].upTo ? gibibyte * currentPlan.tiers[0].upTo : defaultStorageLimit;
return byteConversion;
}
}, [data, currentPlan]);
const byteConversion = currentPlan?.tiers?.[0].upTo ? gibibyte * currentPlan.tiers[0].upTo : defaultStorageLimit;
return byteConversion;
}, [currentPlan]);
const [componentInViewport, setComponentInViewport] = useState(false);
const storageManagerRef = useRef(/** @type {HTMLDivElement | null} */ (null));

const { maxSpaceLabel, percentUploaded, percentPinned } = useMemo(
const { percentUploaded, percentPinned } = useMemo(
() => ({
maxSpaceLabel: `${Math.floor(limit / tebibyte)} ${content.max_space_tib_label}`,
percentUploaded: Math.min((uploaded / limit) * 100, 100),
percentPinned: Math.min((psaPinned / limit) * 100, 100),
}),
[uploaded, psaPinned, limit, content]
[uploaded, psaPinned, limit]
);

useEffect(() => {
Expand Down Expand Up @@ -116,19 +111,11 @@ const StorageManager = ({ className = '', content }) => {
standard: 'iec',
})}
</span>
{currentPlan?.id === 'earlyAdopter' ? (
<>
&nbsp;of <span className="storage-number">{maxSpaceLabel}</span> used
</>
) : (
<>
&nbsp;of{' '}
<span className="storage-number">
{currentPlan?.tiers?.[0].upTo ? formatAsStorageAmount(currentPlan?.tiers?.[0].upTo) : ''}
</span>{' '}
used
</>
)}
&nbsp;of{' '}
<span className="storage-number">
{currentPlan?.tiers?.[0].upTo ? formatAsStorageAmount(currentPlan?.tiers?.[0].upTo) : ''}
</span>{' '}
used
<Tooltip content={content.tooltip_total}>
<InfoIcon />
</Tooltip>
Expand Down
Expand Up @@ -121,9 +121,6 @@ const AccountPlansModal = ({
if (typeof currentPlan === 'undefined') {
throw new Error('Change plan modal form submitted without selected plan');
}
if (currentPlan.id === 'earlyAdopter') {
throw new Error('Change plan modal form submitted with early adopter plan, but it must be a paid plan');
}
if (currentPlan.id !== 'free' && currentPlan.id !== 'pro' && currentPlan.id !== 'lite') {
throw new Error('Unrecognized plan');
}
Expand Down
57 changes: 17 additions & 40 deletions packages/website/components/contexts/plansContext.js
Expand Up @@ -7,16 +7,6 @@
* @property {StoragePrice|Plan} price
*/

/**
* @typedef {null} EarlyAdopterStorageSubscription
* When api's /user/payment .subscription.storage is null, there is no storage subscription.
* And that is what we sometimes render as 'Early Adopter'
*/

/**
* @typedef {'earlyAdopter'} EarlyAdopterPlanId
*/

/**
* @typedef {object} StripeTier
* @property {number|null} flatAmount
Expand All @@ -34,7 +24,23 @@
* @property {StripeTier[]} [tiers]
*/

export const sharedPlans = [
export const freePlan = {
id: /** @type {const} */ ('free'),
description: 'You are currently on the free tier. You can use our service up to 5GiB without being charged.',
label: 'Free',
bandwidth: '10',
isPreferred: false,
tiers: [
{
flatAmount: 0,
unitAmount: 0,
upTo: 5,
},
],
};

export const plans = [
freePlan,
{
id: /** @type {const} */ ('lite'),
description: 'For those that want to take advantage of more storage',
Expand Down Expand Up @@ -74,32 +80,3 @@ export const sharedPlans = [
],
},
];

export const freePlan = {
id: /** @type {const} */ ('free'),
description: 'You are currently on the free tier. You can use our service up to 5GiB without being charged.',
label: 'Free',
bandwidth: '10',
isPreferred: false,
tiers: [
{
flatAmount: 0,
unitAmount: 0,
upTo: 5,
},
],
};

export const earlyAdopterPlan = {
id: /** @type {const} */ ('earlyAdopter'),
isPreferred: true,
bandwidth: null,
description:
'As an early adopter we appreciate your support and can continue to use the storage you are already accustomed to.',
label: 'Early Adopter',
tiers: [],
};

export const plans = [freePlan, ...sharedPlans];
export const plansEarly = [earlyAdopterPlan, ...sharedPlans];
export const plansAll = [freePlan, earlyAdopterPlan, ...sharedPlans];
22 changes: 4 additions & 18 deletions packages/website/hooks/use-payment.js
Expand Up @@ -2,7 +2,7 @@ import { useState, useEffect, useMemo } from 'react';

import { userBillingSettings } from '../lib/api';
import constants from '../lib/constants';
import { earlyAdopterPlan, plans, plansEarly } from '../components/contexts/plansContext';
import { freePlan, plans } from '../components/contexts/plansContext';

/**
* @typedef {import('../components/contexts/plansContext').Plan} Plan
Expand Down Expand Up @@ -42,19 +42,6 @@ export const usePayment = () => {
loadPaymentSettings();
}, [needsFetchPaymentSettings]);

// When storageSubscription is null, user sees a version of planList that contains 'Early Adopter' instead of 'free'
/** @type {Array<Plan>} */
const planList = useMemo(() => {
if (typeof paymentSettings === 'undefined') {
return plans;
}
const storageSubscription = paymentSettings.subscription.storage;
if (storageSubscription === null) {
return plansEarly;
}
return plans;
}, [paymentSettings]);

// whenever the optimisticCurrentPlan is set, enqueue a fetch of actual payment settings
useEffect(() => {
if (optimisticCurrentPlan) {
Expand All @@ -72,10 +59,9 @@ export const usePayment = () => {
}
const storageSubscription = paymentSettings.subscription.storage;
if (!storageSubscription) {
// user has no storage subscription, show early adopter plan
return earlyAdopterPlan;
return freePlan;
}
const matchingStandardPlan = planList.find(plan => {
const matchingStandardPlan = plans.find(plan => {
return plan.id === storageSubscription.price;
});

Expand All @@ -84,7 +70,7 @@ export const usePayment = () => {
}

return matchingStandardPlan;
}, [planList, paymentSettings, optimisticCurrentPlan]);
}, [paymentSettings, optimisticCurrentPlan]);

const savedPaymentMethod = useMemo(() => {
return paymentSettings?.paymentMethod;
Expand Down
4 changes: 1 addition & 3 deletions packages/website/lib/api.js
Expand Up @@ -333,8 +333,6 @@ export class UnexpectedAPIResponseError extends APIError {

/**
* @typedef {import('../components/contexts/plansContext').StorageSubscription} StorageSubscription
* @typedef {import('../components/contexts/plansContext').EarlyAdopterStorageSubscription
* } EarlyAdopterStorageSubscription
*/

/**
Expand Down Expand Up @@ -364,7 +362,7 @@ export function isW3STermsOfServiceAgreement(value) {
* Gets/Puts saved user plan and billing settings.
* @param {W3STermsOfServiceAgreement|undefined} agreement
* @param {string} [pmId] - payment method id
* @param {StorageSubscription|EarlyAdopterStorageSubscription} [storageSubscription]
* @param {StorageSubscription} [storageSubscription]
*/
export async function userBillingSettings(agreement, pmId, storageSubscription) {
const putBody =
Expand Down
27 changes: 6 additions & 21 deletions packages/website/pages/account/payment.js
Expand Up @@ -14,7 +14,7 @@ import PaymentTable from '../../components/account/paymentTable.js/paymentTable.
import PaymentMethodCard from '../../components/account/paymentMethodCard/paymentMethodCard.js';
import AccountPlansModal from '../../components/accountPlansModal/accountPlansModal.js';
import AddPaymentMethodForm from '../../components/account/addPaymentMethodForm/addPaymentMethodForm.js';
import { earlyAdopterPlan, plans, plansEarly } from '../../components/contexts/plansContext';
import { plans, freePlan } from '../../components/contexts/plansContext';
import { userBillingSettings } from '../../lib/api';
import GeneralPageData from '../../content/pages/general.json';
import constants from '../../lib/constants.js';
Expand All @@ -23,7 +23,6 @@ import constants from '../../lib/constants.js';
* @typedef {import('../../components/contexts/plansContext').Plan} Plan
* @typedef {import('../../components/contexts/plansContext').StorageSubscription} StorageSubscription
* @typedef {import('../../components/contexts/plansContext').StoragePrice} StoragePrice
* @typedef {import('../../components/contexts/plansContext').EarlyAdopterPlanId} EarlyAdopterPlanId
*/

/**
Expand Down Expand Up @@ -96,19 +95,6 @@ const PaymentSettingsPage = props => {
loadPaymentSettings();
}, [needsFetchPaymentSettings]);

// When storageSubscription is null, user sees a version of planList that contains 'Early Adopter' instead of 'free'
/** @type {Array<Plan>} */
const planList = useMemo(() => {
if (typeof paymentSettings === 'undefined') {
return plans;
}
const storageSubscription = paymentSettings.subscription.storage;
if (storageSubscription === null) {
return plansEarly;
}
return plans;
}, [paymentSettings]);

// whenever the optimisticCurrentPlan is set, enqueue a fetch of actual payment settings
useEffect(() => {
if (optimisticCurrentPlan) {
Expand All @@ -126,15 +112,14 @@ const PaymentSettingsPage = props => {
}
const storageSubscription = paymentSettings.subscription.storage;
if (!storageSubscription) {
// user has no storage subscription, show early adopter plan
return earlyAdopterPlan;
return freePlan;
}
return typeof storageSubscription.price === 'string'
? planList.find(plan => {
? plans.find(plan => {
return plan.id === storageSubscription.price;
})
: storageSubscription.price;
}, [planList, paymentSettings, optimisticCurrentPlan]);
}, [paymentSettings, optimisticCurrentPlan]);
const savedPaymentMethod = useMemo(() => {
return paymentSettings?.paymentMethod;
}, [paymentSettings]);
Expand All @@ -160,7 +145,7 @@ const PaymentSettingsPage = props => {
<Loading message="Fetching user info..." />
) : (
<PaymentTable
plans={planList}
plans={plans}
currentPlan={currentPlan}
setPlanSelection={setPlanSelection}
setIsPaymentPlanModalOpen={setIsPaymentPlanModalOpen}
Expand Down Expand Up @@ -214,7 +199,7 @@ const PaymentSettingsPage = props => {
removePlanQueryParam();
}
}}
planList={planList}
planList={plans}
planSelection={planSelection}
setCurrentPlan={setOptimisticCurrentPlan}
savedPaymentMethod={savedPaymentMethod}
Expand Down

0 comments on commit 81081bd

Please sign in to comment.