Skip to content

Commit

Permalink
feat: /account/payment disables changing plans after scheduled sunset…
Browse files Browse the repository at this point in the history
… date (#2321)

Motivation:
* https://github.com/web3-storage/secrets/issues/23

Notes
* it takes effect when rendering after the date configured by
`NEXT_PUBLIC_W3UP_LAUNCH_SUNSET_START`, which is also the date that is
used inside the announcement banner. We can easily change the exact
logic in the `shouldPreventPlanSwitching` in w3up-launch.js later too
* I got sick of looking at a React warning in browser console about
invalid nesting of div inside p, and it was because payment page Tooltip
(div) was in a p, so I made the Tooltip element name configurable to get
rid of the warning. seems to work ok
  • Loading branch information
gobengo authored Nov 9, 2023
1 parent 4781c8b commit 22799fe
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 15 deletions.
4 changes: 4 additions & 0 deletions .env.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ NEXT_PUBLIC_ENV=dev
# NEXT_PUBLIC_COUNTLY_KEY=
# NEXT_PUBLIC_COUNTLY_URL=

# set to schedule when announcement banners should show about the w3up launch and related product sunsets
# NEXT_PUBLIC_W3UP_LAUNCH_SUNSET_ANNOUNCEMENT_START='2023-11-21T00:00:00Z'
# set to schedule when certain features hide bcause the product has been sunset and w3up is launched
# NEXT_PUBLIC_W3UP_LAUNCH_SUNSET_START='2024-01-10T00:00:00Z'

## ---- cron ------------------------------------------------------------------

Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/website.yml
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ jobs:
NEXT_PUBLIC_COUNTLY_KEY: ${{ secrets.COUNTLY_KEY }}
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY: ${{ secrets.TESTING_STRIPE_PUBLISHABLE_KEY }}
NEXT_PUBLIC_W3UP_LAUNCH_SUNSET_ANNOUNCEMENT_START: ${{ vars.NEXT_PUBLIC_W3UP_LAUNCH_SUNSET_ANNOUNCEMENT_START }}
NEXT_PUBLIC_W3UP_LAUNCH_SUNSET_START: ${{ vars.NEXT_PUBLIC_W3UP_LAUNCH_SUNSET_START }}
DID_DOCUMENT_ID: ${{ secrets.STAGING_DID_DOCUMENT_ID }}
DID_DOCUMENT_PRIMARY_DID_KEY: ${{ secrets.STAGING_DID_DOCUMENT_PRIMARY_DID_KEY }}
- name: Add to web3.storage
Expand Down Expand Up @@ -296,6 +297,7 @@ jobs:
NEXT_PUBLIC_COUNTLY_KEY: ${{ secrets.COUNTLY_KEY }}
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY: ${{ secrets.STRIPE_PUBLISHABLE_KEY }}
NEXT_PUBLIC_W3UP_LAUNCH_SUNSET_ANNOUNCEMENT_START: ${{ vars.NEXT_PUBLIC_W3UP_LAUNCH_SUNSET_ANNOUNCEMENT_START }}
NEXT_PUBLIC_W3UP_LAUNCH_SUNSET_START: ${{ vars.NEXT_PUBLIC_W3UP_LAUNCH_SUNSET_START }}
DID_DOCUMENT_ID: ${{ secrets.PRODUCTION_DID_DOCUMENT_ID }}
DID_DOCUMENT_PRIMARY_DID_KEY: ${{ secrets.PRODUCTION_DID_DOCUMENT_PRIMARY_DID_KEY }}
- name: Add to web3.storage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,37 @@ import { formatAsStorageAmount, formatCurrency } from '../../../lib/utils.js';

const getAdditionalStoragePrice = price => (typeof price === 'number' ? `${formatCurrency(price / 100)} / GiB` : 'N/A');

const PaymentTable = ({ plans: plansProp, currentPlan, setPlanSelection, setIsPaymentPlanModalOpen }) => {
/**
* @typedef {import('../../../components/contexts/plansContext.js').Plan} Plan
* @typedef {import('../../../components/contexts/plansContext.js').StorageSubscription} StorageSubscription
* @typedef {import('../../../components/contexts/plansContext.js').StoragePrice} StoragePrice
*/

/**
* @param {object} props
* @param {Plan} [props.currentPlan]
* @param {boolean} [props.disablePlanSwitching] - whether to disable plan switching e.g. hide 'select plan' buttons
* @param {Plan[]} props.plans
* @param {(isOpen: boolean) => void} props.setIsPaymentPlanModalOpen
* @param {(plan?: Plan) => void} props.setPlanSelection
*/
const PaymentTable = ({
plans: plansProp,
currentPlan,
setPlanSelection,
setIsPaymentPlanModalOpen,
disablePlanSwitching,
}) => {
const plans = useMemo(() => {
const isCurrentPlanStandard = ['free', 'lite', 'pro'].includes(currentPlan?.id);
const isCurrentPlanStandard = currentPlan ? ['free', 'lite', 'pro'].includes(currentPlan?.id) : false;

if (!isCurrentPlanStandard) {
return [currentPlan, ...plansProp.slice(1)];
return [...(currentPlan ? [currentPlan] : []), ...plansProp.slice(1)];
}

return plansProp;
}, [plansProp, currentPlan]);

const shouldShowSelectPlanButtons = !disablePlanSwitching;
return (
<>
{currentPlan && (
Expand All @@ -42,7 +62,10 @@ const PaymentTable = ({ plans: plansProp, currentPlan, setPlanSelection, setIsPa
<p>Base Storage Capacity</p>
<p>
Additional Storage{' '}
<Tooltip content="This is a charge for storage use above your limit. Please refer to <a href='/terms' target='_blank'>Terms of Service</a> for more information.">
<Tooltip
content="This is a charge for storage use above your limit. Please refer to <a href='/terms' target='_blank'>Terms of Service</a> for more information."
element="span"
>
<InfoIcon />
</Tooltip>
</p>
Expand All @@ -62,19 +85,21 @@ const PaymentTable = ({ plans: plansProp, currentPlan, setPlanSelection, setIsPa
</div>
</div>

{!currentPlan?.tiers?.length && plan.id === currentPlan.id ? (
{!currentPlan?.tiers?.length && plan.id === currentPlan?.id ? (
<div className="billing-plan-details">
<p className="preferred-desc">{currentPlan.description}</p>
</div>
) : (
<div className="billing-plan-details">
<p>{formatAsStorageAmount(plan.tiers?.[0]?.upTo)}</p>
<p>{formatAsStorageAmount(plan.tiers?.[0]?.upTo ?? 0)}</p>
<p>{getAdditionalStoragePrice(plan.tiers?.[1]?.unitAmount)}</p>
<p>{plan.bandwidth ? `${formatAsStorageAmount(plan.bandwidth)} / month` : 'N/A'}</p>
<p>
{plan.bandwidth ? `${formatAsStorageAmount(parseInt(plan.bandwidth, 10) ?? 0)} / month` : 'N/A'}
</p>
</div>
)}

{currentPlan?.id !== plan.id && (
{shouldShowSelectPlanButtons && currentPlan?.id !== plan.id && (
<Button
variant="light"
disabled={currentPlan?.isPreferred}
Expand Down
11 changes: 10 additions & 1 deletion packages/website/components/w3up-launch.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react';

const sunsetStartEnv = process.env.NEXT_PUBLIC_W3UP_LAUNCH_SUNSET_START ?? '2023-01-10T00:00:00Z';
const sunsetStartEnv = process.env.NEXT_PUBLIC_W3UP_LAUNCH_SUNSET_START ?? '2024-01-10T00:00:00Z';
const sunsetStartDate = new Date(Date.parse(sunsetStartEnv));

/**
Expand All @@ -27,6 +27,15 @@ export const shouldShowSunsetAnnouncement = (at = new Date(), announcementStartD
return announcementStartDate && at > announcementStartDate;
};

/**
* return whether the website should prevent allowing customers to switch their storage subscription plan.
* @param {Date} at - time at which to return whether to show the announcement
* @param {Date|undefined} [startDate] - when to begin preventing
*/
export const shouldPreventPlanSwitching = (at = new Date(), startDate = sunsetStartDate) => {
return at > startDate;
};

export const w3upLaunchConfig = {
type: 'W3upLaunchConfig',
stages: {
Expand Down
9 changes: 5 additions & 4 deletions packages/website/modules/zero/components/tooltip/tooltip.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import clsx from 'clsx';
import { BsFillInfoCircleFill } from 'react-icons/bs';


/**
* @typedef {Object} InfoProps
* @property {string} content
* @property {string} [position]
* @property {React.ReactNode} [icon]
* @property {string|React.ReactNode} [children]
* @property {keyof JSX.IntrinsicElements} [element] - element name to use as root
* @prop {string} [className]
*/

Expand All @@ -16,13 +16,14 @@ import { BsFillInfoCircleFill } from 'react-icons/bs';
* @param {InfoProps} props
* @returns
*/
const Tooltip = ({ children, content, icon = null, className, position }) => {
const Tooltip = ({ children, content, icon = null, className, position, element = 'div' }) => {
const Tag = element;
return (
<div role="tooltip" className={clsx(className, 'Tooltip', position)}>
<Tag role="tooltip" className={clsx(className, 'Tooltip', position)}>
{!children && (icon || <BsFillInfoCircleFill />)}
{children}
<span className="tooltip-content" dangerouslySetInnerHTML={{ __html: content }} />
</div>
</Tag>
);
};

Expand Down
7 changes: 6 additions & 1 deletion packages/website/pages/account/payment.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ 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';
import { W3upMigrationRecommendationCopy, shouldShowSunsetAnnouncement } from '../../components/w3up-launch.js';
import {
W3upMigrationRecommendationCopy,
shouldShowSunsetAnnouncement,
shouldPreventPlanSwitching,
} from '../../components/w3up-launch.js';
import * as PageBannerPortal from '../../components/page-banner/page-banner-portal.js';

/**
Expand Down Expand Up @@ -155,6 +159,7 @@ const PaymentSettingsPage = props => {
currentPlan={currentPlan}
setPlanSelection={setPlanSelection}
setIsPaymentPlanModalOpen={setIsPaymentPlanModalOpen}
disablePlanSwitching={shouldPreventPlanSwitching()}
/>
)}

Expand Down

0 comments on commit 22799fe

Please sign in to comment.