Skip to content

Commit c84f285

Browse files
committed
salesloft sync after adding tags
1 parent 15d2e0f commit c84f285

File tree

4 files changed

+58
-4
lines changed

4 files changed

+58
-4
lines changed

src/packages/conat/hub/api/system.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ export const system = {
2121
adminResetPasswordLink: authFirst,
2222
sendEmailVerification: authFirst,
2323
deletePassport: authFirst,
24+
25+
adminSalesloftSync: authFirst,
2426
};
2527

2628
export interface System {
@@ -95,6 +97,12 @@ export interface System {
9597
user_account_id: string;
9698
}) => Promise<string>;
9799

100+
// user must be an admin or get an error. Sync's the given salesloft accounts.
101+
adminSalesloftSync: (opts: {
102+
account_id?: string;
103+
account_ids: string[];
104+
}) => Promise<void>;
105+
98106
sendEmailVerification: (opts: {
99107
account_id?: string;
100108
only_verify?: boolean;

src/packages/frontend/frame-editors/crm-editor/views/view-menu/tag-accounts.tsx

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import type { ColumnsType } from "../../fields";
1515
import { Set as iSet } from "immutable";
1616
import { plural } from "@cocalc/util/misc";
1717
import ShowError from "@cocalc/frontend/components/error";
18-
import { map as awaitMap } from "awaiting";
18+
import { map as awaitMap, delay } from "awaiting";
1919
const MAX_PARALLEL_TASKS = 15;
2020

2121
interface Props {
@@ -43,6 +43,7 @@ export default function TagAccounts({
4343
const [progress, setProgress] = useState<number>(0);
4444
const [error, setError] = useState<string>("");
4545
const [add, setAdd] = useState<boolean>(true);
46+
const [status, setStatus] = useState<string>("");
4647

4748
if (selected == null) {
4849
return null;
@@ -69,7 +70,7 @@ export default function TagAccounts({
6970
let goal = selected.size;
7071
const check = () => {
7172
done += 1;
72-
setProgress(Math.round((done * 100) / goal));
73+
setProgress(Math.round((done * 90) / goal));
7374
};
7475

7576
const task = async (account_id) => {
@@ -104,9 +105,23 @@ export default function TagAccounts({
104105
}
105106
check();
106107
};
107-
await awaitMap(Array.from(selected), MAX_PARALLEL_TASKS, task);
108+
const account_ids = Array.from(selected);
109+
setStatus("Updating database tags");
110+
await awaitMap(account_ids, MAX_PARALLEL_TASKS, task);
111+
refresh();
112+
setStatus("Syncing users with Salesloft");
113+
try {
114+
await webapp_client.conat_client.hub.system.adminSalesloftSync({
115+
account_ids,
116+
});
117+
} catch (err) {
118+
errors.push(err);
119+
}
120+
setProgress(100);
121+
await delay(250);
108122
setValue("");
109123
} finally {
124+
setStatus("");
110125
refresh();
111126
if (errors.length > 0) {
112127
setError(errors.join(" \n"));
@@ -163,13 +178,17 @@ export default function TagAccounts({
163178
message={
164179
<>
165180
The above tags will be {add ? "added to" : "removed from"} each
166-
selected account.
181+
selected account, then we will attempt to sync each with
182+
salesloft. Syncing with salesloft happens in the backend, and
183+
might not always succeed (e.g., if the user has no email).
167184
</>
168185
}
169186
/>
170187
{loading && (
171188
<div>
172189
<Progress percent={progress} />
190+
<hr />
191+
{status}
173192
</div>
174193
)}
175194
{error && <hr />}

src/packages/server/conat/api/system.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ import isAdmin from "@cocalc/server/accounts/is-admin";
99
import search from "@cocalc/server/accounts/search";
1010
export { getNames } from "@cocalc/server/accounts/get-name";
1111
import { callback2 } from "@cocalc/util/async-utils";
12+
import getLogger from "@cocalc/backend/logger";
13+
14+
const logger = getLogger("server:conat:api:system");
1215

1316
export function ping() {
1417
return { now: Date.now() };
@@ -128,3 +131,26 @@ export async function deletePassport(opts: {
128131
}): Promise<void> {
129132
await delete_passport(db(), opts);
130133
}
134+
135+
import { sync as salesloftSync } from "@cocalc/server/salesloft/sync";
136+
export async function adminSalesloftSync({
137+
account_id,
138+
account_ids,
139+
}: {
140+
account_id?: string;
141+
account_ids: string[];
142+
}) {
143+
if (!account_id || !(await isAdmin(account_id))) {
144+
throw Error("must be an admin");
145+
}
146+
(async () => {
147+
// we do not block on this
148+
try {
149+
await salesloftSync(account_ids);
150+
} catch (err) {
151+
logger.debug(`WARNING: issue syncing with salesloft -- ${err}`, {
152+
account_ids,
153+
});
154+
}
155+
})();
156+
}

src/packages/server/salesloft/sync.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ The following are the custom_fields that we actually use:
2626
- cocalc_last_month_spend: amount they spent during the last 30 days, according to daily statements only
2727
- cocalc_last_year_spend: the total amount they have spent during the last year, according to monthly statements
2828
- cocalc_tags: zero or more of 'personal' or 'student' or 'instructor' or 'professional', separated by comma (no space, in alphabetical order)
29+
these can be easily customized in the CRM.
2930
3031
RATE LIMITS:
3132

0 commit comments

Comments
 (0)