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/frontend/account/account-page.tsx
Views: 687
1
/*
2
* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
3
* License: MS-RSL – see LICENSE.md for details
4
*/
5
6
/*
7
The account page. This is what you see when you
8
click "Account" in the upper right. It has tabs
9
for different account related information
10
and configuration.
11
*/
12
13
import { useEffect } from "react";
14
import { Space } from "antd";
15
import { useIntl } from "react-intl";
16
import { SignOut } from "@cocalc/frontend/account/sign-out";
17
import { AntdTabItem, Col, Row, Tabs } from "@cocalc/frontend/antd-bootstrap";
18
import {
19
React,
20
redux,
21
useIsMountedRef,
22
useTypedRedux,
23
useWindowDimensions,
24
} from "@cocalc/frontend/app-framework";
25
import { Icon, Loading } from "@cocalc/frontend/components";
26
import { cloudFilesystemsEnabled } from "@cocalc/frontend/compute";
27
import CloudFilesystems from "@cocalc/frontend/compute/cloud-filesystem/cloud-filesystems";
28
import { labels } from "@cocalc/frontend/i18n";
29
import PurchasesPage from "@cocalc/frontend/purchases/purchases-page";
30
import StatementsPage from "@cocalc/frontend/purchases/statements-page";
31
import SubscriptionsPage from "@cocalc/frontend/purchases/subscriptions-page";
32
import { SupportTickets } from "@cocalc/frontend/support";
33
import {
34
KUCALC_COCALC_COM,
35
KUCALC_ON_PREMISES,
36
} from "@cocalc/util/db-schema/site-defaults";
37
import { AccountPreferences } from "./account-preferences";
38
import { I18NSelector } from "./i18n-selector";
39
import { LicensesPage } from "./licenses/licenses-page";
40
import { PublicPaths } from "./public-paths/public-paths";
41
import { SSHKeysPage } from "./ssh-keys/global-ssh-keys";
42
import { UpgradesPage } from "./upgrades/upgrades-page";
43
import { appBasePath } from "@cocalc/frontend/customize/app-base-path";
44
45
export const AccountPage: React.FC = () => {
46
const intl = useIntl();
47
48
const { width: windowWidth } = useWindowDimensions();
49
const isWide = windowWidth > 800;
50
51
const active_page = useTypedRedux("account", "active_page");
52
const is_logged_in = useTypedRedux("account", "is_logged_in");
53
const account_id = useTypedRedux("account", "account_id");
54
const is_anonymous = useTypedRedux("account", "is_anonymous");
55
const kucalc = useTypedRedux("customize", "kucalc");
56
const ssh_gateway = useTypedRedux("customize", "ssh_gateway");
57
const is_commercial = useTypedRedux("customize", "is_commercial");
58
const get_api_key = useTypedRedux("page", "get_api_key");
59
60
function handle_select(key: string): void {
61
switch (key) {
62
case "billing":
63
redux.getActions("billing").update_customer();
64
break;
65
case "support":
66
break;
67
case "signout":
68
return;
69
}
70
redux.getActions("account").set_active_tab(key);
71
redux.getActions("account").push_state(`/${key}`);
72
}
73
74
function render_account_tab(): AntdTabItem {
75
return {
76
key: "account",
77
label: (
78
<span>
79
<Icon name="wrench" /> {intl.formatMessage(labels.preferences)}
80
</span>
81
),
82
children: (active_page == null || active_page === "account") && (
83
<AccountPreferences />
84
),
85
};
86
}
87
88
function render_special_tabs(): AntdTabItem[] {
89
// adds a few conditional tabs
90
if (is_anonymous) {
91
// None of these make any sense for a temporary anonymous account.
92
return [];
93
}
94
const items: AntdTabItem[] = [];
95
if (is_commercial) {
96
items.push({
97
key: "purchases",
98
label: (
99
<span>
100
<Icon name="money" /> {intl.formatMessage(labels.purchases)}
101
</span>
102
),
103
children: active_page === "purchases" && <PurchasesPage />,
104
});
105
items.push({
106
key: "subscriptions",
107
label: (
108
<span>
109
<Icon name="calendar" /> {intl.formatMessage(labels.subscriptions)}
110
</span>
111
),
112
children: active_page === "subscriptions" && <SubscriptionsPage />,
113
});
114
items.push({
115
key: "statements",
116
label: (
117
<span>
118
<Icon name="money" /> {intl.formatMessage(labels.statements)}
119
</span>
120
),
121
children: active_page === "statements" && <StatementsPage />,
122
});
123
}
124
125
if (
126
kucalc === KUCALC_COCALC_COM ||
127
kucalc === KUCALC_ON_PREMISES ||
128
is_commercial
129
) {
130
items.push({
131
key: "licenses",
132
label: (
133
<span>
134
<Icon name="key" /> {intl.formatMessage(labels.licenses)}
135
</span>
136
),
137
children: active_page === "licenses" && <LicensesPage />,
138
});
139
}
140
141
if (ssh_gateway || kucalc === KUCALC_COCALC_COM) {
142
items.push({
143
key: "ssh-keys",
144
label: (
145
<span>
146
<Icon name="key" /> {intl.formatMessage(labels.ssh_keys)}
147
</span>
148
),
149
children: active_page === "ssh-keys" && <SSHKeysPage />,
150
});
151
}
152
if (is_commercial) {
153
items.push({
154
key: "support",
155
label: (
156
<span>
157
<Icon name="medkit" /> {intl.formatMessage(labels.support)}
158
</span>
159
),
160
children: active_page === "support" && <SupportTickets />,
161
});
162
}
163
items.push({
164
key: "public-files",
165
label: (
166
<span>
167
<Icon name="share-square" />{" "}
168
{intl.formatMessage(labels.published_files)}
169
</span>
170
),
171
children: active_page === "public-files" && <PublicPaths />,
172
});
173
if (is_commercial && kucalc === KUCALC_COCALC_COM) {
174
items.push({
175
key: "upgrades",
176
label: (
177
<span>
178
<Icon name="arrow-circle-up" />{" "}
179
{intl.formatMessage(labels.upgrades)}
180
</span>
181
),
182
children: active_page === "upgrades" && <UpgradesPage />,
183
});
184
}
185
if (cloudFilesystemsEnabled()) {
186
items.push({
187
key: "cloud-filesystems",
188
label: (
189
<>
190
<Icon name="disk-round" />{" "}
191
{intl.formatMessage(labels.cloud_file_system)}
192
</>
193
),
194
children: <CloudFilesystems />,
195
});
196
}
197
198
return items;
199
}
200
201
function renderExtraContent() {
202
return (
203
<Space>
204
<I18NSelector isWide={isWide} />
205
<SignOut everywhere={false} highlight={true} narrow={!isWide} />
206
</Space>
207
);
208
}
209
210
function render_logged_in_view(): JSX.Element {
211
if (!account_id) {
212
return (
213
<div style={{ textAlign: "center", paddingTop: "15px" }}>
214
<Loading theme={"medium"} />
215
</div>
216
);
217
}
218
if (is_anonymous) {
219
return (
220
<div style={{ margin: "15px 10%" }}>
221
<AccountPreferences />
222
</div>
223
);
224
}
225
226
const tabs: AntdTabItem[] = [
227
render_account_tab(),
228
...render_special_tabs(),
229
];
230
231
return (
232
<Row>
233
<Col md={12}>
234
<Tabs
235
activeKey={active_page ?? "account"}
236
onSelect={handle_select}
237
animation={false}
238
tabBarExtraContent={renderExtraContent()}
239
items={tabs}
240
/>
241
</Col>
242
</Row>
243
);
244
}
245
246
return (
247
<div
248
className="smc-vfill"
249
style={{ overflow: "auto", paddingLeft: "5%", paddingRight: "5%" }}
250
>
251
{is_logged_in && !get_api_key ? (
252
render_logged_in_view()
253
) : (
254
<RedirectToNextApp />
255
)}
256
</div>
257
);
258
};
259
260
function RedirectToNextApp({}) {
261
const isMountedRef = useIsMountedRef();
262
263
useEffect(() => {
264
const f = () => {
265
if (isMountedRef.current) {
266
// didn't get signed in so go to landing page
267
window.location.href = appBasePath;
268
}
269
};
270
setTimeout(f, 5000);
271
}, []);
272
273
return <Loading theme="medium" />;
274
}
275
276