Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/frontend/account/upgrades/upgrades-page.tsx
1503 views
1
/*
2
* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
3
* License: MS-RSL – see LICENSE.md for details
4
*/
5
6
import { Col, Panel, Row } from "@cocalc/frontend/antd-bootstrap";
7
import {
8
Component,
9
rclass,
10
redux,
11
rtypes,
12
} from "@cocalc/frontend/app-framework";
13
import { A, Icon, Loading, Gap } from "@cocalc/frontend/components";
14
import { appBasePath } from "@cocalc/frontend/customize/app-base-path";
15
import { plural, round1 } from "@cocalc/util/misc";
16
import { PROJECT_UPGRADES } from "@cocalc/util/schema";
17
import { Progress } from "antd";
18
import { Map } from "immutable";
19
import { join } from "path";
20
import { PolicyPricingPageUrl, SiteName } from "../../customize";
21
import "./project-upgrades-table";
22
import { ProjectUpgradesTable } from "./project-upgrades-table";
23
export { tmp as UpgradesPage };
24
declare var DEBUG: boolean;
25
26
interface reduxProps {
27
stripe_customer?: Map<string, any>;
28
project_map?: Map<string, any>;
29
all_projects_have_been_loaded?: boolean;
30
}
31
32
class UpgradesPage extends Component<reduxProps> {
33
static reduxProps() {
34
return {
35
projects: {
36
project_map: rtypes.immutable.Map,
37
all_projects_have_been_loaded: rtypes.bool,
38
},
39
account: {
40
stripe_customer: rtypes.immutable.Map,
41
},
42
};
43
}
44
45
private render_no_upgrades(): React.JSX.Element {
46
return (
47
<div>
48
<h3>Upgrades are no longer available</h3>
49
Please visit <A href={join(appBasePath, "store")}>the new store</A>,
50
explore <A href={join(appBasePath, "pricing")}>our products</A>, or{" "}
51
<A href={join(appBasePath, "billing/subscriptions")}>
52
view your legacy upgrade subscriptions
53
</A>
54
.
55
</div>
56
);
57
}
58
59
private render_have_upgrades(): React.JSX.Element {
60
return (
61
<div style={{ margin: "10px 0" }}>
62
<h3>
63
Thank you for supporting <SiteName />
64
</h3>
65
<div style={{ color: "#666" }}>
66
<p>
67
You have some now deprecated "quota upgrades". They are listed
68
below, along with how you have applied them to projects. You can
69
adjust your project upgrade contribution from the settings page in
70
any project.
71
</p>
72
<p>
73
Going forward, we offer many{" "}
74
<A href={PolicyPricingPageUrl}> pricing and subscription options</A>
75
, which you can subscribe to in the{" "}
76
<A href={join(appBasePath, "store")}>Store</A>.
77
</p>
78
</div>
79
<Gap />
80
</div>
81
);
82
}
83
84
private render_upgrade(param, amount, used, darker): React.JSX.Element {
85
const info = PROJECT_UPGRADES.params[param];
86
const n = round1(amount != null ? info.display_factor * amount : 0);
87
let u = round1(used != null ? info.display_factor * used : 0);
88
if (u > n) {
89
u = n;
90
}
91
const percent_used = Math.round((u / n) * 100);
92
return (
93
<Row key={param} style={darker ? { backgroundColor: "#eee" } : undefined}>
94
<Col sm={2}>{info.display}</Col>
95
<Col sm={3}>
96
<Row>
97
<Col sm={5}>
98
{u != null ? (
99
<span>
100
{u} {plural(u, info.display_unit)}
101
</span>
102
) : undefined}
103
</Col>
104
<Col sm={7}>
105
<Progress percent={percent_used} />
106
</Col>
107
</Row>
108
</Col>
109
<Col sm={2}>
110
{n != null ? (
111
<span>
112
{n} {plural(n, info.display_unit)}
113
</span>
114
) : undefined}
115
</Col>
116
<Col sm={5} style={{ color: "#666" }}>
117
{info.desc}
118
</Col>
119
</Row>
120
);
121
}
122
123
private render_upgrade_rows(upgrades, used): React.JSX.Element[] {
124
let i = 1;
125
const result: React.JSX.Element[] = [];
126
for (let prop of PROJECT_UPGRADES.field_order) {
127
const amount = upgrades[prop];
128
i += 1;
129
result.push(this.render_upgrade(prop, amount, used[prop], i % 2 === 0));
130
}
131
return result;
132
}
133
134
private render_upgrades(): React.JSX.Element {
135
const upgrades = redux.getStore("account").get_total_upgrades();
136
const used = redux
137
.getStore("projects")
138
.get_total_upgrades_you_have_applied();
139
if (upgrades == null || used == null) {
140
return this.render_no_upgrades();
141
}
142
143
// Ensure that all projects loaded -- this can change used above, which is fine,
144
// and would re-render this component. The issue is that it's conceivable you have
145
// a project nobody has touched for a month, which has upgrades applied to it.
146
redux.getActions("projects").load_all_projects();
147
148
return (
149
<Panel
150
header={
151
<span>
152
<Icon name="tachometer-alt" /> Upgrades from your subscriptions and
153
course packages
154
</span>
155
}
156
>
157
<Row key="header">
158
<Col sm={2}>
159
<strong>Quota</strong>
160
</Col>
161
<Col sm={3}>
162
<strong>Used</strong>
163
</Col>
164
<Col sm={2}>
165
<strong>Purchased</strong>
166
</Col>
167
<Col sm={5}>
168
<strong>Description</strong>
169
</Col>
170
</Row>
171
{this.render_upgrade_rows(upgrades, used)}
172
</Panel>
173
);
174
}
175
176
public render(): React.JSX.Element {
177
if (this.props.project_map == null) {
178
return <Loading theme={"medium"} />;
179
}
180
if (!this.props.all_projects_have_been_loaded) {
181
// See https://github.com/sagemathinc/cocalc/issues/3802
182
redux.getActions("projects").load_all_projects();
183
return <Loading theme={"medium"} />;
184
}
185
if (
186
!DEBUG &&
187
!this.props.stripe_customer?.getIn(["subscriptions", "total_count"])
188
) {
189
return this.render_no_upgrades();
190
} else {
191
return (
192
<div>
193
{this.render_have_upgrades()}
194
{this.render_upgrades()}
195
<ProjectUpgradesTable />
196
</div>
197
);
198
}
199
}
200
}
201
202
const tmp = rclass(UpgradesPage);
203
204