Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/next/pages/pricing/subscriptions.tsx
1450 views
1
/*
2
* This file is part of CoCalc: Copyright © 2022 Sagemath, Inc.
3
* License: MS-RSL – see LICENSE.md for details
4
*/
5
6
import { Alert, Layout, List } from "antd";
7
import dayjs from "dayjs";
8
9
import { Icon, IconName } from "@cocalc/frontend/components/icon";
10
import { LicenseIdleTimeouts } from "@cocalc/util/consts/site-license";
11
import { compute_cost } from "@cocalc/util/licenses/purchase/compute-cost";
12
import {
13
CURRENT_VERSION,
14
discount_monthly_pct,
15
discount_yearly_pct,
16
MIN_QUOTE,
17
} from "@cocalc/util/licenses/purchase/consts";
18
import { PurchaseInfo } from "@cocalc/util/licenses/purchase/types";
19
import { money } from "@cocalc/util/licenses/purchase/utils";
20
import { COLORS } from "@cocalc/util/theme";
21
import Footer from "components/landing/footer";
22
import Head from "components/landing/head";
23
import Header from "components/landing/header";
24
import PricingItem, { Line } from "components/landing/pricing-item";
25
import { Paragraph, Title } from "components/misc";
26
import A from "components/misc/A";
27
import {
28
applyLicense,
29
listedPrices,
30
pricingQuestions,
31
} from "components/share/pricing";
32
import { LinkToStore, StoreConf } from "components/store/link";
33
import { MAX_WIDTH } from "lib/config";
34
import { Customize } from "lib/customize";
35
import withCustomize from "lib/with-customize";
36
37
import type { JSX } from "react";
38
39
function addMonth(date: Date): Date {
40
return dayjs(date).add(30, "days").add(12, "hours").toDate();
41
}
42
43
interface Item {
44
title: string;
45
icon: IconName;
46
projects: number;
47
disk: number;
48
shared_ram: number;
49
shared_cores: number;
50
academic?: boolean;
51
uptime?: string;
52
monthly: number;
53
yearly: number;
54
conf: StoreConf;
55
}
56
57
const now = new Date();
58
59
const hobby: Item = (() => {
60
const conf = {
61
run_limit: 2,
62
disk: 3,
63
ram: 2,
64
cpu: 1,
65
uptime: "short",
66
user: "academic",
67
} as const;
68
69
const info: PurchaseInfo = {
70
version: CURRENT_VERSION,
71
type: "quota",
72
user: conf.user,
73
upgrade: "custom",
74
quantity: conf.run_limit,
75
subscription: "monthly",
76
start: now,
77
end: addMonth(now),
78
custom_ram: conf.ram,
79
custom_cpu: conf.cpu,
80
custom_disk: conf.disk,
81
custom_member: true,
82
custom_dedicated_ram: 0,
83
custom_dedicated_cpu: 0,
84
custom_uptime: conf.uptime,
85
};
86
87
const priceM = compute_cost(info);
88
const priceY = compute_cost({ ...info, subscription: "yearly" });
89
90
return {
91
title: "Hobbyist",
92
icon: "battery-quarter",
93
projects: conf.run_limit,
94
shared_ram: conf.ram,
95
shared_cores: conf.cpu,
96
disk: conf.disk,
97
academic: true,
98
uptime: LicenseIdleTimeouts[conf.uptime].labelShort,
99
monthly: priceM.cost,
100
yearly: priceY.cost,
101
conf,
102
};
103
})();
104
105
const academic: Item = (() => {
106
const conf = {
107
run_limit: 3,
108
disk: 10,
109
ram: 5,
110
cpu: 2,
111
uptime: "day",
112
user: "academic",
113
} as const;
114
115
const info: PurchaseInfo = {
116
version: CURRENT_VERSION,
117
type: "quota",
118
user: conf.user,
119
upgrade: "custom",
120
quantity: conf.run_limit,
121
subscription: "monthly",
122
start: now,
123
end: addMonth(now),
124
custom_ram: conf.ram,
125
custom_cpu: conf.cpu,
126
custom_disk: conf.disk,
127
custom_member: true,
128
custom_dedicated_ram: 0,
129
custom_dedicated_cpu: 0,
130
custom_uptime: conf.uptime,
131
};
132
133
const priceM = compute_cost(info);
134
const priceY = compute_cost({ ...info, subscription: "yearly" });
135
136
return {
137
title: "Academic Researcher Group",
138
icon: "battery-half",
139
projects: conf.run_limit,
140
shared_ram: conf.ram,
141
shared_cores: conf.cpu,
142
disk: conf.disk,
143
dedicated_cores: 0,
144
academic: true,
145
uptime: LicenseIdleTimeouts[conf.uptime].labelShort,
146
monthly: priceM.cost,
147
yearly: priceY.cost,
148
conf,
149
};
150
})();
151
152
const business: Item = (() => {
153
const conf = {
154
run_limit: 5,
155
disk: 5,
156
ram: 4,
157
cpu: 1,
158
uptime: "medium",
159
user: "business",
160
} as const;
161
162
const info: PurchaseInfo = {
163
version: CURRENT_VERSION,
164
type: "quota",
165
user: conf.user,
166
upgrade: "custom",
167
quantity: conf.run_limit,
168
subscription: "monthly",
169
start: now,
170
end: addMonth(now),
171
custom_ram: conf.ram,
172
custom_cpu: conf.cpu,
173
custom_disk: conf.disk,
174
custom_member: true,
175
custom_dedicated_ram: 0,
176
custom_dedicated_cpu: 0,
177
custom_uptime: conf.uptime,
178
};
179
180
const priceM = compute_cost(info);
181
const priceY = compute_cost({ ...info, subscription: "yearly" });
182
183
return {
184
title: "Business Working Group",
185
icon: "battery-full",
186
projects: conf.run_limit,
187
shared_ram: conf.ram,
188
shared_cores: conf.cpu,
189
disk: conf.disk,
190
academic: false,
191
uptime: LicenseIdleTimeouts[conf.uptime].labelShort,
192
monthly: priceM.cost,
193
yearly: priceY.cost,
194
conf,
195
};
196
})();
197
198
const data: Item[] = [hobby, academic, business];
199
200
function dedicated(): JSX.Element {
201
return (
202
<Alert
203
style={{ margin: "15px 0" }}
204
message="Dedicated Virtual Machines"
205
description={
206
<span style={{ fontSize: "11pt" }}>
207
For more intensive workloads you can also rent a{" "}
208
<A href="/pricing/dedicated">dedicated virtual machine or disk</A>.
209
</span>
210
}
211
type="info"
212
showIcon
213
/>
214
);
215
}
216
217
export default function Subscriptions({ customize }) {
218
const { siteName } = customize;
219
return (
220
<Customize value={customize}>
221
<Head title={`${siteName} – Pricing – Subscriptions`} />
222
<Layout>
223
<Header page="pricing" subPage="subscriptions" />
224
<Layout.Content
225
style={{
226
backgroundColor: "white",
227
}}
228
>
229
<Body />
230
<Footer />
231
</Layout.Content>
232
</Layout>
233
</Customize>
234
);
235
}
236
237
function Body(): JSX.Element {
238
return (
239
<div
240
style={{
241
maxWidth: MAX_WIDTH,
242
margin: "15px auto",
243
padding: "15px",
244
backgroundColor: "white",
245
}}
246
>
247
<Title level={1} style={{ textAlign: "center" }}>
248
<Icon name="calendar" style={{ marginRight: "30px" }} /> CoCalc -
249
Subscriptions
250
</Title>
251
<a id="subscriptions"></a>
252
<Paragraph>
253
Initially, you start using CoCalc under a{" "}
254
<A href="https://doc.cocalc.com/trial.html">free trial plan</A> in order
255
to test out the service. If CoCalc works for you, please purchase a
256
license.
257
</Paragraph>
258
<Paragraph>
259
A subscription provides you with a{" "}
260
<A href="https://doc.cocalc.com/licenses.html">license key</A> for{" "}
261
<A href="https://doc.cocalc.com/project-settings.html#licenses">
262
upgrading your projects
263
</A>{" "}
264
or other projects where you are a collaborator — everyone using an
265
upgraded project benefits equally. Such a{" "}
266
<A href="/billing/subscriptions">subscription</A>{" "}
267
<b>automatically renews</b> at the end of each period. You can{" "}
268
<A href="/billing/subscriptions">
269
<b>cancel at any time</b>
270
</A>
271
.
272
</Paragraph>
273
274
{applyLicense()}
275
276
<Title level={2}>Examples</Title>
277
<Paragraph>
278
We list three typical configurations below, which you can{" "}
279
<A href="/store/site-license">modify and purchase here</A>. All
280
parameters can be adjusted to fit your needs. Listed upgrades are for
281
each project. Exact prices may vary. Below ${MIN_QUOTE}, only online
282
purchases are available (no purchase orders). Subscriptions receive a{" "}
283
{discount_monthly_pct}% discount for monthly and {discount_yearly_pct}%
284
for yearly periods.
285
</Paragraph>
286
<List
287
grid={{ gutter: 15, column: 3, xs: 1, sm: 1 }}
288
dataSource={data}
289
renderItem={(item) => (
290
<PricingItem title={item.title} icon={item.icon}>
291
<Line amount={item.projects} desc="Projects" />
292
<Line amount={item.shared_ram} desc="Shared RAM per project" />
293
<Line amount={item.shared_cores} desc="Shared CPU per project" />
294
<Line amount={item.disk} desc="Disk space per project" />
295
<Line amount={item.uptime} desc="Idle timeout" />
296
<Line amount={"∞"} desc="Collaborators" />
297
{item.academic ? (
298
<Line amount="40%" desc="Academic discount" />
299
) : (
300
<Line amount="" desc="" />
301
)}
302
303
<br />
304
<br />
305
<div>
306
<span
307
style={{
308
fontWeight: "bold",
309
fontSize: "18pt",
310
color: COLORS.GRAY_DD,
311
}}
312
>
313
{money(item.monthly, true)}
314
</span>{" "}
315
/ month
316
</div>
317
<div>
318
<span
319
style={{
320
fontWeight: "bold",
321
fontSize: "18pt",
322
color: COLORS.GRAY_DD,
323
}}
324
>
325
{money(item.yearly, true)}
326
</span>{" "}
327
/ year
328
</div>
329
<LinkToStore conf={item.conf} />
330
</PricingItem>
331
)}
332
/>
333
{listedPrices()}
334
{pricingQuestions()}
335
{dedicated()}
336
</div>
337
);
338
}
339
340
export async function getServerSideProps(context) {
341
return await withCustomize({ context });
342
}
343
344