CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
sagemathinc

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

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