Skip to content

Commit 184176a

Browse files
authored
feat: self-serve yearly (#8428)
* feat: self-serve yearly * fix: manage addons * fix: manage addons * fix typecheck * fix: annual text
1 parent c8d0094 commit 184176a

File tree

15 files changed

+226
-645
lines changed

15 files changed

+226
-645
lines changed

packages/app/src/app/components/WorkspaceSetup/Summary.tsx

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ import { useActions, useAppState } from 'app/overmind';
55
import styled from 'styled-components';
66
import { useWorkspaceSubscription } from 'app/hooks/useWorkspaceSubscription';
77
import {
8-
CreditAddon,
8+
CreditAddonType,
99
SubscriptionPackage,
1010
} from 'app/overmind/namespaces/checkout/types';
11+
import { SubscriptionInterval } from 'app/graphql/types';
1112
import { fadeAnimation } from './elements';
1213
import { WorkspaceFlow } from './types';
1314

@@ -25,7 +26,8 @@ export const Summary: React.FC<{
2526
hasUpcomingChange,
2627
} = checkout;
2728

28-
const isAnnual = newSubscription?.basePlan.id === 'flex-annual';
29+
const isAnnual =
30+
newSubscription?.billingInterval === SubscriptionInterval.Yearly;
2931
const allowAnnualSwitch = flow !== 'manage-addons';
3032

3133
return (
@@ -52,17 +54,19 @@ export const Summary: React.FC<{
5254
title={currentSubscription ? 'New plan' : 'Plan summary'}
5355
subscriptionPackage={newSubscription}
5456
editable={allowChanges}
55-
onIncrementItem={addon => {
56-
actions.checkout.addCreditsPackage(addon);
57+
onIncrementItem={addonId => {
58+
actions.checkout.addCreditsPackage(addonId);
5759
track('Checkout - Increment Addon Item', {
5860
from: flow,
61+
addonId,
5962
currentPlan: isPro ? 'pro' : 'free',
6063
});
6164
}}
62-
onDecrementItem={addon => {
63-
actions.checkout.removeCreditsPackage(addon);
65+
onDecrementItem={addonId => {
66+
actions.checkout.removeCreditsPackage(addonId);
6467
track('Checkout - Decrement Addon Item', {
6568
from: flow,
69+
addonId,
6670
currentPlan: isPro ? 'pro' : 'free',
6771
});
6872
}}
@@ -75,7 +79,12 @@ export const Summary: React.FC<{
7579
id="recurring"
7680
on={isAnnual}
7781
onChange={() => {
78-
actions.checkout.selectPlan(isAnnual ? 'flex' : 'flex-annual');
82+
actions.checkout.selectPlan({
83+
plan: 'flex',
84+
billingInterval: isAnnual
85+
? SubscriptionInterval.Monthly
86+
: SubscriptionInterval.Yearly,
87+
});
7988

8089
track('Checkout - Toggle recurring type', {
8190
from: flow,
@@ -87,8 +96,6 @@ export const Summary: React.FC<{
8796
<Text color="#fff" as="label" htmlFor="recurring">
8897
Annual (Save 30%)
8998
</Text>
90-
91-
{isAnnual && <Text>24 hour processing time</Text>}
9299
</Stack>
93100
</Stack>
94101
)}
@@ -106,8 +113,8 @@ interface PlanSummaryProps {
106113
title: string;
107114
subscriptionPackage: SubscriptionPackage;
108115
editable: boolean;
109-
onDecrementItem?: (addon: CreditAddon) => void;
110-
onIncrementItem?: (addon: CreditAddon) => void;
116+
onDecrementItem?: (id: CreditAddonType) => void;
117+
onIncrementItem?: (id: CreditAddonType) => void;
111118
}
112119

113120
const PlanSummary: React.FC<PlanSummaryProps> = ({
@@ -129,10 +136,8 @@ const PlanSummary: React.FC<PlanSummaryProps> = ({
129136
>
130137
<Stack direction="horizontal" justify="space-between" gap={2}>
131138
<Stack direction="vertical">
132-
<Text color="#fff">
133-
{subscriptionPackage.basePlan.name} plan base
134-
</Text>
135-
<Text>{subscriptionPackage.basePlan.credits} VM credits</Text>
139+
<Text color="#fff">Monthly base plan</Text>
140+
<Text>{subscriptionPackage.basePlan.credits} VM credits/month</Text>
136141
</Stack>
137142
<Text color="#fff">${subscriptionPackage.basePlan.price}</Text>
138143
</Stack>
@@ -145,13 +150,13 @@ const PlanSummary: React.FC<PlanSummaryProps> = ({
145150
justify="space-between"
146151
gap={2}
147152
>
148-
<Text color="#fff">{item.addon.credits} VM credits</Text>
153+
<Text color="#fff">{item.addon.credits} VM credits/month</Text>
149154
<Stack align="center">
150155
{editable && (
151156
<QuantityCounter
152157
quantity={item.quantity}
153-
onIncrement={() => onIncrementItem?.(item.addon)}
154-
onDecrement={() => onDecrementItem?.(item.addon)}
158+
onIncrement={() => onIncrementItem?.(item.addon.id)}
159+
onDecrement={() => onDecrementItem?.(item.addon.id)}
155160
/>
156161
)}
157162

@@ -167,9 +172,11 @@ const PlanSummary: React.FC<PlanSummaryProps> = ({
167172
<Stack direction="vertical">
168173
<Text color="#fff">
169174
Total cost per{' '}
170-
{subscriptionPackage.basePlan.id === 'flex-annual' ? 'year' : 'month'}
175+
{subscriptionPackage.billingInterval === SubscriptionInterval.Yearly
176+
? 'year'
177+
: 'month'}
171178
</Text>
172-
<Text>{subscriptionPackage.totalCredits} VM credits</Text>
179+
<Text>{subscriptionPackage.totalCredits} VM credits/month</Text>
173180
</Stack>
174181

175182
<Text color="#fff">${subscriptionPackage.totalPrice}</Text>

packages/app/src/app/components/WorkspaceSetup/steps/Addons.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ const CreditAddonButton = ({
135135
currentPlan: isPro ? 'pro' : 'free',
136136
addonId: addon.id,
137137
});
138-
actions.checkout.addCreditsPackage(addon);
138+
actions.checkout.addCreditsPackage(addon.id);
139139
}}
140140
>
141141
<Stack
@@ -163,7 +163,7 @@ const StyledPrice = ({ addon }: { addon: CreditAddon }) => (
163163
${addon.fullPrice}
164164
</Text>
165165
)}{' '}
166-
${addon.price}
166+
${addon.priceMonthly}
167167
</Text>
168168
{addon.discount && (
169169
<Text size={2} color={addon.discount === 30 ? '#BDB1F6' : '#DCF76E'}>

packages/app/src/app/components/WorkspaceSetup/steps/ChangeAddons.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import * as dashboardUrls from '@codesandbox/common/lib/utils/url-generator/dash
55

66
import { useURLSearchParams } from 'app/hooks/useURLSearchParams';
77
import { useActions, useAppState } from 'app/overmind';
8+
import { SubscriptionInterval } from 'app/graphql/types';
89
import { StepProps } from '../types';
910
import { StepHeader } from '../StepHeader';
1011
import { AnimatedStep } from '../elements';
@@ -21,6 +22,10 @@ export const ChangeAddons: React.FC<StepProps> = ({
2122
const { getQueryParam } = useURLSearchParams();
2223
const urlWorkspaceId = getQueryParam('workspace');
2324
const [isSubmitting, setSubmitting] = React.useState(false);
25+
const billingFactor =
26+
checkout.newSubscription.billingInterval === SubscriptionInterval.Monthly
27+
? 1
28+
: 12;
2429

2530
const handleSubmit = async e => {
2631
e.preventDefault();
@@ -88,7 +93,10 @@ export const ChangeAddons: React.FC<StepProps> = ({
8893
size={5}
8994
color={change.quantity > 0 ? '#A3EC98' : '#DD5F5F'}
9095
>
91-
{changeSign}${change.addon.price * Math.abs(change.quantity)}
96+
{changeSign}$
97+
{change.addon.price *
98+
billingFactor *
99+
Math.abs(change.quantity)}
92100
</Text>
93101
</Stack>
94102
);

0 commit comments

Comments
 (0)