Skip to content

Commit

Permalink
feat: remove sandbox addons (#8385)
Browse files Browse the repository at this point in the history
* feat: remove sandbox addons

* fix: remove shareable
  • Loading branch information
alexnm committed Mar 11, 2024
1 parent 856903c commit 062423f
Show file tree
Hide file tree
Showing 10 changed files with 16 additions and 267 deletions.
33 changes: 0 additions & 33 deletions packages/app/src/app/components/WorkspaceSetup/Summary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,8 @@ export const Summary: React.FC<{ allowChanges: boolean }> = ({
const {
selectedPlan,
creditAddons,
sandboxAddons,
totalCredits,
totalPrice,
totalSandboxes,
spendingLimit,
availableBasePlans,
} = checkout;
Expand Down Expand Up @@ -56,7 +54,6 @@ export const Summary: React.FC<{ allowChanges: boolean }> = ({
<Stack direction="vertical">
<Text color="#fff">{basePlan.name} plan base</Text>
<Text>{basePlan.credits} VM credits</Text>
<Text>{basePlan.sandboxes} sandboxes</Text>
</Stack>
<Text color="#fff">${basePlan.price}</Text>
</Stack>
Expand Down Expand Up @@ -97,42 +94,12 @@ export const Summary: React.FC<{ allowChanges: boolean }> = ({
</Stack>
</AnimatedLineItem>
))}

{sandboxAddons.map(item => (
<AnimatedLineItem
direction="horizontal"
key={item.addon.id}
align="center"
justify="space-between"
gap={2}
>
<Text color="#fff">{item.addon.sandboxes} sandboxes</Text>
<Stack align="center">
{allowChanges && (
<QuantityCounter
quantity={item.quantity}
onIncrement={() =>
actions.checkout.addSandboxPackage(item.addon)
}
onDecrement={() =>
actions.checkout.removeSandboxPackage(item.addon.id)
}
/>
)}

<Text color="#fff" css={{ width: '48px', textAlign: 'right' }}>
${item.quantity * item.addon.price}
</Text>
</Stack>
</AnimatedLineItem>
))}
</Stack>

<Stack justify="space-between">
<Stack direction="vertical">
<Text color="#fff">Total cost per month</Text>
<Text>{totalCredits} VM credits</Text>
<Text>{totalSandboxes} sandboxes</Text>
</Stack>

<Text color="#fff">${totalPrice}</Text>
Expand Down
80 changes: 3 additions & 77 deletions packages/app/src/app/components/WorkspaceSetup/steps/Addons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@ import styled from 'styled-components';
import { useWorkspaceSubscription } from 'app/hooks/useWorkspaceSubscription';
import { useURLSearchParams } from 'app/hooks/useURLSearchParams';
import { useLocation } from 'react-router-dom';
import {
CreditAddon,
SandboxAddon,
} from 'app/overmind/namespaces/checkout/types';
import { CreditAddon } from 'app/overmind/namespaces/checkout/types';
import { StepProps } from '../types';
import { StepHeader } from '../StepHeader';
import { AnimatedStep } from '../elements';
Expand All @@ -22,7 +19,7 @@ export const Addons: React.FC<StepProps> = ({
numberOfSteps,
}) => {
const {
checkout: { availableCreditAddons, availableSandboxAddons },
checkout: { availableCreditAddons },
} = useAppState();
const { isPro } = useWorkspaceSubscription();
const { checkout } = useActions();
Expand Down Expand Up @@ -95,44 +92,6 @@ export const Addons: React.FC<StepProps> = ({
</Element>
</Stack>

<Stack direction="vertical" gap={8}>
<Stack direction="vertical" gap={2}>
<Text color="#e5e5e5" size={6}>
Would you like to add more Sandboxes to your plan?
</Text>
<Text>
Sandboxes are powered by your browser and don&apos;t require
credits to run.{' '}
<Text
css={{ textDecoration: 'none', color: '#DCF76E' }}
as="a"
target="_blank"
href="https://codesandbox.io/docs/learn/plans/ubb"
>
Learn more
</Text>
</Text>
</Stack>
<Element
css={{
display: 'grid',
gridTemplateColumns: '1fr 1fr 1fr',
width: '100%',
gap: '16px',
'@media (max-width: 1460px)': {
gridTemplateColumns: '1fr 1fr',
},
'@media (max-width: 1170px)': {
gridTemplateColumns: '1fr',
},
}}
>
{Object.values(availableSandboxAddons).map(addon => (
<SandboxAddonButton key={addon.id} addon={addon} />
))}
</Element>
</Stack>

<Button autoWidth size="large" onClick={handleSubmit}>
Next
</Button>
Expand Down Expand Up @@ -175,40 +134,7 @@ const CreditAddonButton = ({ addon }: { addon: CreditAddon }) => {
);
};

const SandboxAddonButton = ({ addon }: { addon: SandboxAddon }) => {
const actions = useActions();
const { isPro } = useWorkspaceSubscription();
const { pathname } = useLocation();
const isUpgrading = pathname.includes('upgrade');

return (
<StyledAddonButton
onClick={() => {
track('Checkout - Click on addon', {
from: isUpgrading ? 'upgrade' : 'create-workspace',
currentPlan: isPro ? 'pro' : 'free',
addonId: addon.id,
});
actions.checkout.addSandboxPackage(addon);
}}
>
<Stack
css={{
width: '100%',
justifyContent: 'space-between',
}}
gap={4}
>
<Stack direction="vertical">
<Text color="#e5e5e5">{addon.sandboxes} Sandboxes</Text>
</Stack>
<StyledPrice addon={addon} />
</Stack>
</StyledAddonButton>
);
};

const StyledPrice = ({ addon }: { addon: CreditAddon | SandboxAddon }) => (
const StyledPrice = ({ addon }: { addon: CreditAddon }) => (
<Stack direction="vertical" align="flex-end">
<Text color="#e5e5e5" css={{ textWrap: 'nowrap' }}>
{addon.fullPrice && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ export const ChangePlan: React.FC<StepProps> = ({
Pro plan
</Text>
<Text>{checkout.totalCredits} VM credits</Text>
<Text>{checkout.totalSandboxes} Sandboxes</Text>
</Stack>
<Text size={6} color="#e5e5e5">
${checkout.totalPrice} / month
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ export const Plans: React.FC<StepProps> = ({
<PlanFeatures
itemIcon="plus"
heading="Add-ons"
features={['More VM credits', 'More Sandboxes']}
features={['More VM credits']}
/>
</StyledCard>
<StyledCard
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export const FREE_FEATURES: PricingPlanFeatures = {
vmType: `4 vCPUs<br/>8 GB RAM`,
privateProject: true,
shareableLinks: true,
privateNPM: false,
privateNPM: true,
liveSessions: true,
apiAccess: true,
protectedPreviews: false,
Expand All @@ -52,15 +52,14 @@ export const PRO_FEATURES: PricingPlanFeatures = {
members: 20,
storage: `50 GB<br/>
<small>more with add-ons</small>`,
sandboxes: `100<br/>
<small>more with add-ons</small>`,
sandboxes: Number.MAX_SAFE_INTEGER,
devboxes: Number.MAX_SAFE_INTEGER,
repositories: Number.MAX_SAFE_INTEGER,
drafts: Number.MAX_SAFE_INTEGER,
vmType: `16 vCPUs<br />32 GB RAM`,
privateProject: true,
shareableLinks: true,
privateNPM: false,
privateNPM: true,
liveSessions: true,
apiAccess: true,
protectedPreviews: false,
Expand All @@ -76,7 +75,7 @@ export const ENTERPRISE_FEATURES: PricingPlanFeatures = {
name: 'Enterprise',
members: Number.MAX_SAFE_INTEGER,
storage: 'Custom',
sandboxes: 'Custom',
sandboxes: Number.MAX_SAFE_INTEGER,
devboxes: Number.MAX_SAFE_INTEGER,
repositories: Number.MAX_SAFE_INTEGER,
drafts: Number.MAX_SAFE_INTEGER,
Expand Down
3 changes: 1 addition & 2 deletions packages/app/src/app/overmind/effects/api/types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Sandbox } from '@codesandbox/common/lib/types';
import {
CreditAddonType,
SandboxAddonType,
VMType,
} from 'app/overmind/namespaces/checkout/types';

Expand Down Expand Up @@ -68,7 +67,7 @@ export type VMTier = {

export type APIPricingResult = {
addons: Record<
CreditAddonType | SandboxAddonType,
CreditAddonType,
{ credits: number; cost_month: number; sandboxes: number }
>;
base: {
Expand Down
87 changes: 4 additions & 83 deletions packages/app/src/app/overmind/namespaces/checkout/actions.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
import type { Context } from 'app/overmind';
import {
CreditAddon,
CreditAddonType,
SandboxAddon,
SandboxAddonType,
PlanType,
} from './types';
import { CreditAddon, CreditAddonType, PlanType } from './types';
import { DEFAULT_SPENDING_LIMIT } from './constants';

export const fetchPrices = async ({ state, effects }: Context) => {
Expand All @@ -19,21 +13,13 @@ export const fetchPrices = async ({ state, effects }: Context) => {
...state.checkout.availableBasePlans.flex,
credits: proPricing.credits,
price: proPricing.cost_month / 100,
sandboxes: proPricing.sandboxes,
storage: proPricing.storage,
};

Object.values(state.checkout.availableCreditAddons).forEach(creditAddon => {
creditAddon.price = proAddons[creditAddon.id].cost_month / 100;
creditAddon.credits = proAddons[creditAddon.id].credits;
});

Object.values(state.checkout.availableSandboxAddons).forEach(
sandboxAddon => {
sandboxAddon.price = proAddons[sandboxAddon.id].cost_month / 100;
sandboxAddon.sandboxes = proAddons[sandboxAddon.id].sandboxes;
}
);
} catch {
// Silent fail as client values can be used as defaults
}
Expand Down Expand Up @@ -85,57 +71,12 @@ export const removeCreditsPackage = (
actions.checkout.recomputeTotals();
};

export const addSandboxPackage = (
{ state, actions }: Context,
addon: SandboxAddon
) => {
const addonInCheckoutAlready = state.checkout.sandboxAddons.find(
item => item.addon.id === addon.id
);

if (addonInCheckoutAlready) {
addonInCheckoutAlready.quantity++;
} else {
state.checkout.sandboxAddons.push({ addon, quantity: 1 });
}

actions.checkout.recomputeTotals();
};

export const removeSandboxPackage = (
{ state, actions }: Context,
addonId: SandboxAddonType
) => {
const addonItem = state.checkout.sandboxAddons.find(
item => item.addon.id === addonId
);

if (!addonItem) {
return;
}

addonItem.quantity--;

if (addonItem.quantity === 0) {
state.checkout.sandboxAddons = state.checkout.sandboxAddons.filter(
item => item.addon.id !== addonId
);
}

actions.checkout.recomputeTotals();
};

export const recomputeTotals = ({ state }: Context) => {
if (!state.checkout.selectedPlan) {
return;
}

const {
availableBasePlans,
selectedPlan,
creditAddons,
sandboxAddons,
} = state.checkout;
const { availableBasePlans, selectedPlan, creditAddons } = state.checkout;

const basePlan = availableBasePlans[selectedPlan];

Expand All @@ -144,36 +85,21 @@ export const recomputeTotals = ({ state }: Context) => {
0
);

const totalSandboxAddonsPrice = sandboxAddons.reduce(
(acc, item) => acc + item.addon.price * item.quantity,
0
);

state.checkout.totalPrice =
basePlan.price + totalCreditAddonsPrice + totalSandboxAddonsPrice;
state.checkout.totalPrice = basePlan.price + totalCreditAddonsPrice;

state.checkout.totalCredits =
basePlan.credits +
creditAddons.reduce(
(acc, item) => acc + item.addon.credits * item.quantity,
0
);

state.checkout.totalSandboxes =
basePlan.sandboxes +
sandboxAddons.reduce(
(acc, item) => acc + item.addon.sandboxes * item.quantity,
0
);
};

export const clearCheckout = ({ state }: Context) => {
state.checkout.selectedPlan = null;
state.checkout.creditAddons = [];
state.checkout.sandboxAddons = [];
state.checkout.totalPrice = 0;
state.checkout.totalCredits = 0;
state.checkout.totalSandboxes = 0;
state.checkout.spendingLimit = DEFAULT_SPENDING_LIMIT;
state.checkout.convertProToUBBCharge = null;
};
Expand Down Expand Up @@ -261,18 +187,13 @@ export const convertToUsageBilling = async (
};

export const getFlatAddonsList = ({ state }: Context): string[] => {
const { creditAddons, sandboxAddons } = state.checkout;
const { creditAddons } = state.checkout;
const addons: string[] = [];
creditAddons.forEach(item => {
for (let i = 0; i < item.quantity; i++) {
addons.push(item.addon.id);
}
});
sandboxAddons.forEach(item => {
for (let i = 0; i < item.quantity; i++) {
addons.push(item.addon.id);
}
});

return addons;
};
Loading

0 comments on commit 062423f

Please sign in to comment.