Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/frontend/app/sign-in-action.ts
5980 views
1
/*
2
Do something somewhat friendly when a user signs in for the first time,
3
either after creating an account or being signed out.
4
5
For now:
6
7
- ensure they are a collab on at least one project
8
- open the most recent project they actively used and show the +New page
9
10
That's it for now.
11
*/
12
13
import { delay } from "awaiting";
14
import { redux } from "@cocalc/frontend/app-framework";
15
import { once } from "@cocalc/util/async-utils";
16
import { webapp_client } from "@cocalc/frontend/webapp-client";
17
import { cmp } from "@cocalc/util/misc";
18
import { QueryParams } from "@cocalc/frontend/misc/query-params";
19
20
export default async function signInAction() {
21
const signIn = QueryParams.get("sign-in");
22
if (signIn == null) {
23
return;
24
}
25
QueryParams.remove("sign-in");
26
await delay(1); // so projects store is created (not in sync initial load loop)
27
const project_id = await getProject();
28
const actions = redux.getActions("projects");
29
actions.open_project({ project_id, switch_to: true, target: "new" });
30
await actions.start_project(project_id);
31
}
32
33
async function create(title = "My First Project") {
34
const project_id = await webapp_client.project_client.create({
35
title,
36
description: "",
37
});
38
const projects = redux.getStore("projects");
39
// wait until projects_map is loaded, so we know what projects the users has (probably)
40
while (projects.getIn(["project_map", project_id]) == null) {
41
await once(projects, "change");
42
}
43
return project_id;
44
}
45
46
async function getProject(): Promise<string> {
47
const projects = redux.getStore("projects");
48
// wait until projects_map is loaded, so we know what projects the users has (probably)
49
while (projects.get("project_map") == null) {
50
await once(projects, "change");
51
}
52
const account = redux.getStore("account");
53
while (account.get("created") == null) {
54
await once(account, "change");
55
}
56
57
const created = account.get("created");
58
let project_map = projects.get("project_map")!;
59
if (project_map.size == 0) {
60
// no known projects -- could be a new account, or could be an old account and no *recent* projects
61
if (
62
(created?.valueOf() ?? Date.now()) >=
63
Date.now() - 2 * 24 * 60 * 60 * 1000
64
) {
65
// new account -- make a project
66
return await create("My First Project");
67
} else {
68
// old account but no projects -- try loading all.
69
const projectActions = redux.getActions("projects");
70
await projectActions.load_all_projects();
71
project_map = projects.get("project_map")!;
72
if (project_map.size == 0) {
73
// still nothing -- just create
74
return await create();
75
}
76
}
77
}
78
79
const account_id = account.get("account_id");
80
81
// now there should be at least one project in project_map.
82
// Is there a non-deleted non-hidden project?
83
const options: any[] = [];
84
for (const [_, project] of project_map) {
85
if (project.get("deleted")) {
86
continue;
87
}
88
if (project.getIn(["users", account_id, "hide"])) {
89
continue;
90
}
91
options.push(project);
92
}
93
if (options.length == 0) {
94
return await create();
95
}
96
97
// Sort the projects by when YOU were last active on the project, or if you were
98
// never active on any project, by when the projects was last_edited.
99
const usedByYou = options.filter((x) => x.getIn(["last_active", account_id]));
100
101
if (usedByYou.length == 0) {
102
// you were never active on any project, so just return project most recently edited
103
options.sort((x, y) => -cmp(x.get("last_edited"), y.get("last_edited")));
104
return options[0].get("project_id");
105
}
106
107
usedByYou.sort(
108
(x, y) =>
109
-cmp(
110
x.getIn(["last_active", account_id]),
111
y.getIn(["last_active", account_id]),
112
),
113
);
114
return usedByYou[0].get("project_id");
115
}
116
117