@rapidmx/crm-plugin 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/apps/shared/components/CrmShell.tsx +27 -7
- package/apps/shared/components/WorkspaceSettings.tsx +150 -56
- package/apps/shared/crmApi.ts +10 -0
- package/dist/apps/shared/components/CrmShell.d.ts +8 -1
- package/dist/apps/shared/components/CrmShell.js +12 -3
- package/dist/apps/shared/components/WorkspaceSettings.d.ts +8 -0
- package/dist/apps/shared/components/WorkspaceSettings.js +73 -17
- package/dist/apps/shared/crmApi.d.ts +8 -0
- package/dist/apps/shared/crmApi.js +2 -0
- package/dist/lib/routes/BaseWorkspaceRoute.js +47 -3
- package/dist/lib/routes/BaseWorkspaceRoute.js.map +1 -1
- package/dist/types/routes/BaseWorkspaceRoute.d.ts +18 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -142,7 +142,7 @@ A deployment administrator has no access to a workspace they aren't a member of.
|
|
|
142
142
|
|
|
143
143
|
| Resource | Endpoints |
|
|
144
144
|
| --- | --- |
|
|
145
|
-
| `workspaces` | `GET /`, `POST /`, `GET/PUT/DELETE /:workspaceUid`, `GET/POST /:workspaceUid/members`, `PUT/DELETE /:workspaceUid/members/:userUid`, `GET/POST /:workspaceUid/senders`, `PUT/DELETE /:workspaceUid/senders/:senderUid` |
|
|
145
|
+
| `workspaces` | `GET /`, `POST /`, `GET/PUT/DELETE /:workspaceUid`, `GET/POST /:workspaceUid/members`, `PUT/DELETE /:workspaceUid/members/:userUid`, `GET/POST /:workspaceUid/senders`, `PUT/DELETE /:workspaceUid/senders/:senderUid`, `POST /:workspaceUid/sendable-mailboxes` (`{ mailboxUids }`: which of them the caller can send from) |
|
|
146
146
|
| `contacts`, `companies` | `GET /:workspaceUid`, `POST /:workspaceUid/search`, `POST /:workspaceUid/bulk`, `POST /:workspaceUid/export`, `GET/PUT/DELETE /:workspaceUid/:uid`, `POST /:workspaceUid` |
|
|
147
147
|
| `properties`, `notes`, `tasks` | `GET /:workspaceUid`, `POST /:workspaceUid/search`, `GET/PUT/DELETE /:workspaceUid/:uid`, `POST /:workspaceUid` |
|
|
148
148
|
| `timeline` | `GET /:workspaceUid/:subjectType/:subjectUid` |
|
|
@@ -26,6 +26,7 @@ import AppShell, { AppShellProps } from "@rapidmx/web-client/shared/components/l
|
|
|
26
26
|
import Alert from "@rapidmx/web-client/lib/components/feedback/Alert.js";
|
|
27
27
|
import Button from "@rapidmx/web-client/lib/components/buttons/Button.js";
|
|
28
28
|
import FormField from "@rapidmx/web-client/lib/components/forms/FormField.js";
|
|
29
|
+
import Modal from "@rapidmx/web-client/lib/components/overlays/Modal.js";
|
|
29
30
|
import { Workspace, createWorkspace, errorMessage, listWorkspaces } from "../crmApi.js";
|
|
30
31
|
|
|
31
32
|
/** The props every CRM page receives from the server (the `www` host's), passed straight to its shell. */
|
|
@@ -34,6 +35,9 @@ export type CrmPageProps = Omit<AppShellProps, "active">;
|
|
|
34
35
|
/** The CRM's sections, each a page under `/crm`. */
|
|
35
36
|
export type CrmSection = "contacts" | "companies" | "lists" | "deals" | "pipelines" | "segments" | "forms" | "templates" | "campaigns" | "automations" | "scoring" | "tasks" | "imports" | "reports" | "integrations" | "settings";
|
|
36
37
|
|
|
38
|
+
/** The workspace switcher's choice that opens the "New workspace" dialog rather than switching. */
|
|
39
|
+
export const NEW_WORKSPACE = "__new__";
|
|
40
|
+
|
|
37
41
|
/** Where the selected workspace is remembered between visits (per browser). */
|
|
38
42
|
export const WORKSPACE_STORAGE_KEY = "rapidmx.crm.workspace";
|
|
39
43
|
|
|
@@ -112,12 +116,14 @@ function remember(workspaceUid: string): void {
|
|
|
112
116
|
/**
|
|
113
117
|
* The frame of every CRM page: the web client's app chrome (with CRM highlighted on the app rail), a sidebar with the workspace
|
|
114
118
|
* switcher and the CRM's sections, and the page. It loads the caller's workspaces and picks one (`?w=`, else the last used, else the
|
|
115
|
-
* first); a caller with none is asked to create one. Pages read the selection with
|
|
119
|
+
* first); a caller with none is asked to create one, and the switcher offers to create another. Pages read the selection with
|
|
120
|
+
* `useCrm()`.
|
|
116
121
|
*/
|
|
117
122
|
export default function CrmShell({ section, children, ...props }: PropsWithChildren<CrmPageProps & { section: CrmSection }>) {
|
|
118
123
|
const [workspaces, setWorkspaces] = useState<Workspace[] | null>(null);
|
|
119
124
|
const [selected, setSelected] = useState<Workspace | null>(null);
|
|
120
125
|
const [error, setError] = useState<string | null>(null);
|
|
126
|
+
const [creating, setCreating] = useState<boolean>(false);
|
|
121
127
|
|
|
122
128
|
async function load(preferred: string | null): Promise<void> {
|
|
123
129
|
try {
|
|
@@ -161,12 +167,14 @@ export default function CrmShell({ section, children, ...props }: PropsWithChild
|
|
|
161
167
|
<label htmlFor="crm-workspace" className="text-xs uppercase tracking-wide text-text-muted px-2">
|
|
162
168
|
Workspace
|
|
163
169
|
</label>
|
|
164
|
-
<select id="crm-workspace" className={`${INPUT_CLASS} mb-3`} value={context.workspace.uid} onChange={(event) => switchTo(event.target.value)}
|
|
170
|
+
<select id="crm-workspace" className={`${INPUT_CLASS} mb-3`} value={context.workspace.uid} onChange={(event) => (event.target.value === NEW_WORKSPACE ? setCreating(true) : switchTo(event.target.value))}
|
|
171
|
+
>
|
|
165
172
|
{context.workspaces.map((workspace) => (
|
|
166
173
|
<option key={workspace.uid} value={workspace.uid}>
|
|
167
174
|
{workspace.name}
|
|
168
175
|
</option>
|
|
169
176
|
))}
|
|
177
|
+
<option value={NEW_WORKSPACE}>+ New workspace…</option>
|
|
170
178
|
</select>
|
|
171
179
|
{SECTIONS.map(({ id, label, path, icon: Icon }) => (
|
|
172
180
|
<a
|
|
@@ -187,6 +195,9 @@ export default function CrmShell({ section, children, ...props }: PropsWithChild
|
|
|
187
195
|
{error && <Alert>{error}</Alert>}
|
|
188
196
|
{!error && workspaces === null && <p className="text-sm text-text-muted">Loading…</p>}
|
|
189
197
|
{workspaces !== null && !context && <CreateFirstWorkspace onCreated={(workspace) => switchTo(workspace.uid)} />}
|
|
198
|
+
<Modal open={creating} onClose={() => setCreating(false)} title="New workspace">
|
|
199
|
+
<CreateWorkspaceForm onCreated={(workspace) => switchTo(workspace.uid)} />
|
|
200
|
+
</Modal>
|
|
190
201
|
{context && <CrmContext.Provider value={context}>{children}</CrmContext.Provider>}
|
|
191
202
|
</main>
|
|
192
203
|
</div>
|
|
@@ -196,6 +207,19 @@ export default function CrmShell({ section, children, ...props }: PropsWithChild
|
|
|
196
207
|
|
|
197
208
|
/** The form a caller with no workspace sees. */
|
|
198
209
|
export function CreateFirstWorkspace({ onCreated }: { onCreated: (workspace: Workspace) => void }) {
|
|
210
|
+
return (
|
|
211
|
+
<div className="max-w-md">
|
|
212
|
+
<h1 className="text-lg font-bold tracking-tight mb-2">Create your CRM workspace</h1>
|
|
213
|
+
<p className="text-sm text-text-muted mb-4">
|
|
214
|
+
A workspace holds your team's contacts, companies and tasks. You can invite colleagues to it once it exists.
|
|
215
|
+
</p>
|
|
216
|
+
<CreateWorkspaceForm onCreated={onCreated} />
|
|
217
|
+
</div>
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/** Names and creates a workspace (in the browser's time zone - changeable in its settings), then hands it to `onCreated`. */
|
|
222
|
+
export function CreateWorkspaceForm({ onCreated }: { onCreated: (workspace: Workspace) => void }) {
|
|
199
223
|
const [name, setName] = useState("");
|
|
200
224
|
const [error, setError] = useState<string | null>(null);
|
|
201
225
|
const [saving, setSaving] = useState(false);
|
|
@@ -212,11 +236,7 @@ export function CreateFirstWorkspace({ onCreated }: { onCreated: (workspace: Wor
|
|
|
212
236
|
}
|
|
213
237
|
|
|
214
238
|
return (
|
|
215
|
-
<form onSubmit={submit} className="
|
|
216
|
-
<h1 className="text-lg font-bold tracking-tight mb-2">Create your CRM workspace</h1>
|
|
217
|
-
<p className="text-sm text-text-muted mb-4">
|
|
218
|
-
A workspace holds your team's contacts, companies and tasks. You can invite colleagues to it once it exists.
|
|
219
|
-
</p>
|
|
239
|
+
<form onSubmit={submit} className="min-w-[20rem]">
|
|
220
240
|
{error && <Alert>{error}</Alert>}
|
|
221
241
|
<FormField label="Name" htmlFor="crm-new-workspace">
|
|
222
242
|
<input id="crm-new-workspace" className={INPUT_CLASS} value={name} onChange={(event) => setName(event.target.value)} required />
|
|
@@ -2,14 +2,20 @@
|
|
|
2
2
|
// Copyright (C) 2026 Jean-Philippe Steinmetz
|
|
3
3
|
// SPDX-License-Identifier: MPL-2.0
|
|
4
4
|
///////////////////////////////////////////////////////////////////////////////
|
|
5
|
-
import React, { FormEvent, useEffect, useState } from "react";
|
|
5
|
+
import React, { FormEvent, useEffect, useMemo, useState } from "react";
|
|
6
6
|
import Alert from "@rapidmx/web-client/lib/components/feedback/Alert.js";
|
|
7
7
|
import Button from "@rapidmx/web-client/lib/components/buttons/Button.js";
|
|
8
8
|
import FormField from "@rapidmx/web-client/lib/components/forms/FormField.js";
|
|
9
|
+
import TimeZonePicker from "@rapidmx/web-client/lib/components/pickers/TimeZonePicker.js";
|
|
10
|
+
import { timeZoneOptions } from "@rapidmx/web-client/lib/util/timeZone.js";
|
|
11
|
+
import { listMailboxes } from "@rapidmx/web-client/lib/mail/mailApi.js";
|
|
12
|
+
import { RecipientSuggestion, searchDirectory } from "@rapidmx/web-client/lib/mail/directoryApi.js";
|
|
13
|
+
import RecipientInput from "@rapidmx/web-client/shared/components/mail/compose/RecipientInput.js";
|
|
9
14
|
import {
|
|
10
15
|
CrmObjectType,
|
|
11
16
|
PropertyDefinition,
|
|
12
17
|
PropertyType,
|
|
18
|
+
SendableMailbox,
|
|
13
19
|
WorkspaceMember,
|
|
14
20
|
WorkspaceRole,
|
|
15
21
|
WorkspaceSender,
|
|
@@ -28,6 +34,7 @@ import {
|
|
|
28
34
|
listSenders,
|
|
29
35
|
removeMember,
|
|
30
36
|
removeSender,
|
|
37
|
+
sendableMailboxes,
|
|
31
38
|
updateMember,
|
|
32
39
|
updateWorkspace,
|
|
33
40
|
updateSender,
|
|
@@ -93,13 +100,13 @@ function Details() {
|
|
|
93
100
|
}
|
|
94
101
|
}
|
|
95
102
|
|
|
96
|
-
const fields: [keyof typeof values, string][] = [
|
|
103
|
+
const fields: [Exclude<keyof typeof values, "timezone">, string][] = [
|
|
97
104
|
["name", "Name"],
|
|
98
105
|
["description", "Description"],
|
|
99
|
-
["timezone", "Time zone"],
|
|
100
106
|
["postalAddress", "Postal address (shown in marketing email footers)"],
|
|
101
107
|
["website", "Website"],
|
|
102
108
|
];
|
|
109
|
+
const zones: string[] = useMemo(() => timeZoneOptions(workspace.timezone), [workspace.timezone]);
|
|
103
110
|
return (
|
|
104
111
|
<form onSubmit={save} className="flex flex-col gap-3" aria-label="Workspace details">
|
|
105
112
|
<h2 className="text-sm font-semibold uppercase tracking-wide text-text-muted">Workspace</h2>
|
|
@@ -116,6 +123,13 @@ function Details() {
|
|
|
116
123
|
/>
|
|
117
124
|
</FormField>
|
|
118
125
|
))}
|
|
126
|
+
<FormField label="Time zone" htmlFor="workspace-timezone">
|
|
127
|
+
{canManage ? (
|
|
128
|
+
<TimeZonePicker id="workspace-timezone" value={values.timezone} zones={zones} onChange={(timezone) => setValues((current) => ({ ...current, timezone }))} />
|
|
129
|
+
) : (
|
|
130
|
+
<input id="workspace-timezone" className={INPUT_CLASS} value={values.timezone} disabled />
|
|
131
|
+
)}
|
|
132
|
+
</FormField>
|
|
119
133
|
{canManage && (
|
|
120
134
|
<Button type="submit" className="!w-auto self-start">
|
|
121
135
|
Save
|
|
@@ -125,12 +139,25 @@ function Details() {
|
|
|
125
139
|
);
|
|
126
140
|
}
|
|
127
141
|
|
|
142
|
+
/** The address of an entry of the people field: `Name <address>` or a bare address. */
|
|
143
|
+
export function chipAddress(chip: string): string {
|
|
144
|
+
const match: RegExpExecArray | null = /<([^<>]+)>\s*$/.exec(chip);
|
|
145
|
+
return (match ? match[1] : chip).trim().toLowerCase();
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** Suggests only people with an account on this server - the only ones who can be members. */
|
|
149
|
+
export async function suggestPeople(query: string, options: { limit?: number; signal?: AbortSignal }): Promise<RecipientSuggestion[]> {
|
|
150
|
+
return (await searchDirectory(query, options)).filter((suggestion) => suggestion.kind === "user");
|
|
151
|
+
}
|
|
152
|
+
|
|
128
153
|
function Members() {
|
|
129
154
|
const { workspace, canManage } = useCrm();
|
|
130
155
|
const [members, setMembers] = useState<WorkspaceMember[]>([]);
|
|
131
|
-
const [
|
|
156
|
+
const [text, setText] = useState("");
|
|
157
|
+
const [people, setPeople] = useState<{ chips: string[]; pending: string }>({ chips: [], pending: "" });
|
|
132
158
|
const [role, setRole] = useState<WorkspaceRole>("editor");
|
|
133
159
|
const [error, setError] = useState<string | null>(null);
|
|
160
|
+
const [adding, setAdding] = useState(false);
|
|
134
161
|
|
|
135
162
|
async function load(): Promise<void> {
|
|
136
163
|
setMembers(await listMembers(workspace.uid));
|
|
@@ -150,55 +177,90 @@ function Members() {
|
|
|
150
177
|
}
|
|
151
178
|
}
|
|
152
179
|
|
|
180
|
+
/** Adds everyone in the field; those that fail stay in it, with why. */
|
|
181
|
+
async function add(event: FormEvent): Promise<void> {
|
|
182
|
+
event.preventDefault();
|
|
183
|
+
const entries: string[] = [...people.chips, ...(people.pending.trim() ? [people.pending.trim()] : [])];
|
|
184
|
+
setAdding(true);
|
|
185
|
+
const failed: string[] = [];
|
|
186
|
+
const reasons: string[] = [];
|
|
187
|
+
for (const entry of entries) {
|
|
188
|
+
try {
|
|
189
|
+
await addMember(workspace.uid, { address: chipAddress(entry), role });
|
|
190
|
+
} catch (err) {
|
|
191
|
+
failed.push(entry);
|
|
192
|
+
reasons.push(`${chipAddress(entry)}: ${errorMessage(err, "could not be added.")}`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
setText(failed.join(", "));
|
|
196
|
+
setPeople({ chips: failed, pending: "" });
|
|
197
|
+
setAdding(false);
|
|
198
|
+
try {
|
|
199
|
+
await load();
|
|
200
|
+
setError(reasons.length > 0 ? reasons.join(" ") : null);
|
|
201
|
+
} catch (err) {
|
|
202
|
+
setError([...reasons, errorMessage(err, "Could not load the members.")].join(" "));
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const count: number = people.chips.length + (people.pending.trim() ? 1 : 0);
|
|
153
207
|
return (
|
|
154
208
|
<section aria-label="Members" className="flex flex-col gap-3">
|
|
155
209
|
<h2 className="text-sm font-semibold uppercase tracking-wide text-text-muted">Members</h2>
|
|
156
210
|
{error && <Alert>{error}</Alert>}
|
|
157
211
|
<ul className="flex flex-col divide-y divide-border border-y border-border">
|
|
158
|
-
{members.map((member) =>
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
{
|
|
162
|
-
<
|
|
163
|
-
|
|
164
|
-
className=
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
className="text-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
212
|
+
{members.map((member) => {
|
|
213
|
+
const name: string = member.displayName || member.address || member.userUid;
|
|
214
|
+
return (
|
|
215
|
+
<li key={member.userUid} className="flex items-center gap-3 py-2 text-sm">
|
|
216
|
+
<span className="flex-1 min-w-0">
|
|
217
|
+
<span className="block truncate">{name}</span>
|
|
218
|
+
{member.displayName && member.address && <span className="block truncate text-xs text-text-muted">{member.address}</span>}
|
|
219
|
+
</span>
|
|
220
|
+
{canManage ? (
|
|
221
|
+
<select
|
|
222
|
+
aria-label={`Role of ${name}`}
|
|
223
|
+
className={`${INPUT_CLASS} !w-32`}
|
|
224
|
+
value={member.role}
|
|
225
|
+
onChange={(event) => void act(() => updateMember(workspace.uid, member.userUid, event.target.value as WorkspaceRole), "Could not change the role.")}
|
|
226
|
+
>
|
|
227
|
+
{ROLES.map((entry) => (
|
|
228
|
+
<option key={entry.value} value={entry.value}>
|
|
229
|
+
{entry.label}
|
|
230
|
+
</option>
|
|
231
|
+
))}
|
|
232
|
+
</select>
|
|
233
|
+
) : (
|
|
234
|
+
<span className="text-text-muted">{member.role}</span>
|
|
235
|
+
)}
|
|
236
|
+
{canManage && (
|
|
237
|
+
<button
|
|
238
|
+
type="button"
|
|
239
|
+
className="text-xs text-text-muted hover:text-danger"
|
|
240
|
+
onClick={() => void act(() => removeMember(workspace.uid, member.userUid), "Could not remove the member.")}
|
|
241
|
+
>
|
|
242
|
+
Remove
|
|
243
|
+
</button>
|
|
244
|
+
)}
|
|
245
|
+
</li>
|
|
246
|
+
);
|
|
247
|
+
})}
|
|
188
248
|
</ul>
|
|
189
249
|
{canManage && (
|
|
190
|
-
<form
|
|
191
|
-
className="flex
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
250
|
+
<form className="flex flex-wrap items-start gap-2" aria-label="Add members" onSubmit={(event) => void add(event)}>
|
|
251
|
+
<div className="flex-1 min-w-[18rem]">
|
|
252
|
+
<RecipientInput
|
|
253
|
+
id="crm-new-members"
|
|
254
|
+
label="People"
|
|
255
|
+
ariaLabel="People to add"
|
|
256
|
+
placeholder="Search people by name or address"
|
|
257
|
+
value={text}
|
|
258
|
+
onChange={setText}
|
|
259
|
+
onEdit={(chips, pending) => setPeople({ chips, pending })}
|
|
260
|
+
fetchSuggestions={suggestPeople}
|
|
261
|
+
className={INPUT_CLASS}
|
|
262
|
+
/>
|
|
263
|
+
</div>
|
|
202
264
|
<select aria-label="New member role" className={`${INPUT_CLASS} !w-32`} value={role} onChange={(event) => setRole(event.target.value as WorkspaceRole)}>
|
|
203
265
|
{ROLES.map((entry) => (
|
|
204
266
|
<option key={entry.value} value={entry.value}>
|
|
@@ -206,8 +268,8 @@ function Members() {
|
|
|
206
268
|
</option>
|
|
207
269
|
))}
|
|
208
270
|
</select>
|
|
209
|
-
<Button type="submit" variant="secondary" disabled={
|
|
210
|
-
Add member
|
|
271
|
+
<Button type="submit" variant="secondary" loading={adding} disabled={adding || count === 0} className="!w-auto">
|
|
272
|
+
{count > 1 ? `Add ${count} members` : "Add member"}
|
|
211
273
|
</Button>
|
|
212
274
|
</form>
|
|
213
275
|
)}
|
|
@@ -218,7 +280,8 @@ function Members() {
|
|
|
218
280
|
function Senders() {
|
|
219
281
|
const { workspace, canManage } = useCrm();
|
|
220
282
|
const [senders, setSenders] = useState<WorkspaceSender[]>([]);
|
|
221
|
-
const [
|
|
283
|
+
const [mailboxes, setMailboxes] = useState<SendableMailbox[] | null>(null);
|
|
284
|
+
const [mailboxUid, setMailboxUid] = useState("");
|
|
222
285
|
const [fromName, setFromName] = useState("");
|
|
223
286
|
const [error, setError] = useState<string | null>(null);
|
|
224
287
|
|
|
@@ -230,11 +293,24 @@ function Senders() {
|
|
|
230
293
|
load().catch((err) => setError(errorMessage(err, "Could not load the senders.")));
|
|
231
294
|
}, [workspace.uid]);
|
|
232
295
|
|
|
296
|
+
useEffect(() => {
|
|
297
|
+
if (!canManage) {
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
(async () => {
|
|
301
|
+
const own = await listMailboxes({ limit: 200 });
|
|
302
|
+
setMailboxes(own.length > 0 ? await sendableMailboxes(workspace.uid, own.map((mailbox) => mailbox.uid)) : []);
|
|
303
|
+
})().catch(() => setMailboxes([]));
|
|
304
|
+
}, [workspace.uid, canManage]);
|
|
305
|
+
|
|
306
|
+
const choices: SendableMailbox[] = (mailboxes ?? []).filter((mailbox) => !senders.some((sender) => sender.fromAddress === mailbox.address));
|
|
307
|
+
const chosen: SendableMailbox | undefined = choices.find((mailbox) => mailbox.uid === mailboxUid);
|
|
308
|
+
|
|
233
309
|
async function add(event: FormEvent): Promise<void> {
|
|
234
310
|
event.preventDefault();
|
|
235
311
|
try {
|
|
236
|
-
await addSender(workspace.uid, { fromAddress, ...(fromName.trim() ? { fromName } : {}) });
|
|
237
|
-
|
|
312
|
+
await addSender(workspace.uid, { fromAddress: chosen!.address, ...(fromName.trim() ? { fromName: fromName.trim() } : {}) });
|
|
313
|
+
setMailboxUid("");
|
|
238
314
|
setFromName("");
|
|
239
315
|
setError(null);
|
|
240
316
|
await load();
|
|
@@ -246,7 +322,7 @@ function Senders() {
|
|
|
246
322
|
return (
|
|
247
323
|
<section aria-label="Senders" className="flex flex-col gap-3">
|
|
248
324
|
<h2 className="text-sm font-semibold uppercase tracking-wide text-text-muted">Send as</h2>
|
|
249
|
-
<p className="text-sm text-text-muted">
|
|
325
|
+
<p className="text-sm text-text-muted">Mailboxes the CRM sends from. Replies to mail sent from the CRM arrive in these mailboxes.</p>
|
|
250
326
|
{error && <Alert>{error}</Alert>}
|
|
251
327
|
<ul className="flex flex-col gap-1">
|
|
252
328
|
{senders.map((sender) => (
|
|
@@ -285,11 +361,29 @@ function Senders() {
|
|
|
285
361
|
</li>
|
|
286
362
|
))}
|
|
287
363
|
</ul>
|
|
288
|
-
{canManage && (
|
|
289
|
-
<
|
|
290
|
-
|
|
364
|
+
{canManage && mailboxes !== null && mailboxes.length === 0 && (
|
|
365
|
+
<p className="text-sm text-text-muted">You have no mailbox you can send from. Its owner can add it, or give you send access to it.</p>
|
|
366
|
+
)}
|
|
367
|
+
{canManage && choices.length > 0 && (
|
|
368
|
+
<form className="flex flex-wrap gap-2" aria-label="Add sender" onSubmit={(event) => void add(event)}>
|
|
369
|
+
<select
|
|
370
|
+
aria-label="Mailbox"
|
|
371
|
+
className={`${INPUT_CLASS} !w-72`}
|
|
372
|
+
value={mailboxUid}
|
|
373
|
+
onChange={(event) => {
|
|
374
|
+
setMailboxUid(event.target.value);
|
|
375
|
+
setFromName(choices.find((mailbox) => mailbox.uid === event.target.value)?.displayName ?? "");
|
|
376
|
+
}}
|
|
377
|
+
>
|
|
378
|
+
<option value="">Choose a mailbox…</option>
|
|
379
|
+
{choices.map((mailbox) => (
|
|
380
|
+
<option key={mailbox.uid} value={mailbox.uid}>
|
|
381
|
+
{mailbox.displayName ? `${mailbox.displayName} <${mailbox.address}>` : mailbox.address}
|
|
382
|
+
</option>
|
|
383
|
+
))}
|
|
384
|
+
</select>
|
|
291
385
|
<input aria-label="Sender name" placeholder="Name shown to recipients" className={`${INPUT_CLASS} !w-56`} value={fromName} onChange={(event) => setFromName(event.target.value)} />
|
|
292
|
-
<Button type="submit" variant="secondary" disabled={
|
|
386
|
+
<Button type="submit" variant="secondary" disabled={!chosen} className="!w-auto">
|
|
293
387
|
Add sender
|
|
294
388
|
</Button>
|
|
295
389
|
</form>
|
package/apps/shared/crmApi.ts
CHANGED
|
@@ -209,6 +209,16 @@ export const updateSender = (uid: string, senderUid: string, input: { fromName?:
|
|
|
209
209
|
apiFetch(`/mail/crm/workspaces/${enc(uid)}/senders/${enc(senderUid)}`, json("PUT", input));
|
|
210
210
|
export const addSender = (uid: string, input: { fromAddress: string; fromName?: string; replyToAddress?: string; logEmail?: boolean }): Promise<WorkspaceSender> =>
|
|
211
211
|
apiFetch(`/mail/crm/workspaces/${enc(uid)}/senders`, json("POST", input));
|
|
212
|
+
/** A mailbox the caller may add as a sender. */
|
|
213
|
+
export interface SendableMailbox {
|
|
214
|
+
uid: string;
|
|
215
|
+
address: string;
|
|
216
|
+
displayName: string;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/** Which of `mailboxUids` (the caller's mailboxes) the caller can send from, for the "Send as" picker. */
|
|
220
|
+
export const sendableMailboxes = (uid: string, mailboxUids: string[]): Promise<SendableMailbox[]> =>
|
|
221
|
+
apiFetch(`/mail/crm/workspaces/${enc(uid)}/sendable-mailboxes`, json("POST", { mailboxUids }));
|
|
212
222
|
export const removeSender = (uid: string, senderUid: string): Promise<void> => apiFetch(`/mail/crm/workspaces/${enc(uid)}/senders/${enc(senderUid)}`, json("DELETE"));
|
|
213
223
|
|
|
214
224
|
// Contacts and companies
|
|
@@ -5,6 +5,8 @@ import { Workspace } from "../crmApi.js";
|
|
|
5
5
|
export type CrmPageProps = Omit<AppShellProps, "active">;
|
|
6
6
|
/** The CRM's sections, each a page under `/crm`. */
|
|
7
7
|
export type CrmSection = "contacts" | "companies" | "lists" | "deals" | "pipelines" | "segments" | "forms" | "templates" | "campaigns" | "automations" | "scoring" | "tasks" | "imports" | "reports" | "integrations" | "settings";
|
|
8
|
+
/** The workspace switcher's choice that opens the "New workspace" dialog rather than switching. */
|
|
9
|
+
export declare const NEW_WORKSPACE = "__new__";
|
|
8
10
|
/** Where the selected workspace is remembered between visits (per browser). */
|
|
9
11
|
export declare const WORKSPACE_STORAGE_KEY = "rapidmx.crm.workspace";
|
|
10
12
|
export declare const INPUT_CLASS = "w-full text-sm py-2 px-3 border border-border rounded-sm bg-surface text-text focus:outline-none focus:border-primary";
|
|
@@ -28,7 +30,8 @@ export declare function workspaceHref(path: string, workspaceUid: string): strin
|
|
|
28
30
|
/**
|
|
29
31
|
* The frame of every CRM page: the web client's app chrome (with CRM highlighted on the app rail), a sidebar with the workspace
|
|
30
32
|
* switcher and the CRM's sections, and the page. It loads the caller's workspaces and picks one (`?w=`, else the last used, else the
|
|
31
|
-
* first); a caller with none is asked to create one. Pages read the selection with
|
|
33
|
+
* first); a caller with none is asked to create one, and the switcher offers to create another. Pages read the selection with
|
|
34
|
+
* `useCrm()`.
|
|
32
35
|
*/
|
|
33
36
|
export default function CrmShell({ section, children, ...props }: PropsWithChildren<CrmPageProps & {
|
|
34
37
|
section: CrmSection;
|
|
@@ -37,3 +40,7 @@ export default function CrmShell({ section, children, ...props }: PropsWithChild
|
|
|
37
40
|
export declare function CreateFirstWorkspace({ onCreated }: {
|
|
38
41
|
onCreated: (workspace: Workspace) => void;
|
|
39
42
|
}): React.JSX.Element;
|
|
43
|
+
/** Names and creates a workspace (in the browser's time zone - changeable in its settings), then hands it to `onCreated`. */
|
|
44
|
+
export declare function CreateWorkspaceForm({ onCreated }: {
|
|
45
|
+
onCreated: (workspace: Workspace) => void;
|
|
46
|
+
}): React.JSX.Element;
|
|
@@ -9,7 +9,10 @@ import AppShell from "@rapidmx/web-client/shared/components/layout/AppShell.js";
|
|
|
9
9
|
import Alert from "@rapidmx/web-client/lib/components/feedback/Alert.js";
|
|
10
10
|
import Button from "@rapidmx/web-client/lib/components/buttons/Button.js";
|
|
11
11
|
import FormField from "@rapidmx/web-client/lib/components/forms/FormField.js";
|
|
12
|
+
import Modal from "@rapidmx/web-client/lib/components/overlays/Modal.js";
|
|
12
13
|
import { createWorkspace, errorMessage, listWorkspaces } from "../crmApi.js";
|
|
14
|
+
/** The workspace switcher's choice that opens the "New workspace" dialog rather than switching. */
|
|
15
|
+
export const NEW_WORKSPACE = "__new__";
|
|
13
16
|
/** Where the selected workspace is remembered between visits (per browser). */
|
|
14
17
|
export const WORKSPACE_STORAGE_KEY = "rapidmx.crm.workspace";
|
|
15
18
|
export const INPUT_CLASS = "w-full text-sm py-2 px-3 border border-border rounded-sm bg-surface text-text focus:outline-none focus:border-primary";
|
|
@@ -68,12 +71,14 @@ function remember(workspaceUid) {
|
|
|
68
71
|
/**
|
|
69
72
|
* The frame of every CRM page: the web client's app chrome (with CRM highlighted on the app rail), a sidebar with the workspace
|
|
70
73
|
* switcher and the CRM's sections, and the page. It loads the caller's workspaces and picks one (`?w=`, else the last used, else the
|
|
71
|
-
* first); a caller with none is asked to create one. Pages read the selection with
|
|
74
|
+
* first); a caller with none is asked to create one, and the switcher offers to create another. Pages read the selection with
|
|
75
|
+
* `useCrm()`.
|
|
72
76
|
*/
|
|
73
77
|
export default function CrmShell({ section, children, ...props }) {
|
|
74
78
|
const [workspaces, setWorkspaces] = useState(null);
|
|
75
79
|
const [selected, setSelected] = useState(null);
|
|
76
80
|
const [error, setError] = useState(null);
|
|
81
|
+
const [creating, setCreating] = useState(false);
|
|
77
82
|
async function load(preferred) {
|
|
78
83
|
try {
|
|
79
84
|
const list = await listWorkspaces();
|
|
@@ -105,10 +110,14 @@ export default function CrmShell({ section, children, ...props }) {
|
|
|
105
110
|
reload: () => load(selected.uid),
|
|
106
111
|
}
|
|
107
112
|
: null;
|
|
108
|
-
return (_jsx(AppShell, { ...props, active: "crm", children: _jsxs("div", { className: "flex flex-1 min-w-0 min-h-0", children: [context && (_jsxs("nav", { "aria-label": "CRM", className: "w-56 shrink-0 border-r border-border p-3 flex flex-col gap-1 overflow-y-auto", children: [_jsx("label", { htmlFor: "crm-workspace", className: "text-xs uppercase tracking-wide text-text-muted px-2", children: "Workspace" }),
|
|
113
|
+
return (_jsx(AppShell, { ...props, active: "crm", children: _jsxs("div", { className: "flex flex-1 min-w-0 min-h-0", children: [context && (_jsxs("nav", { "aria-label": "CRM", className: "w-56 shrink-0 border-r border-border p-3 flex flex-col gap-1 overflow-y-auto", children: [_jsx("label", { htmlFor: "crm-workspace", className: "text-xs uppercase tracking-wide text-text-muted px-2", children: "Workspace" }), _jsxs("select", { id: "crm-workspace", className: `${INPUT_CLASS} mb-3`, value: context.workspace.uid, onChange: (event) => (event.target.value === NEW_WORKSPACE ? setCreating(true) : switchTo(event.target.value)), children: [context.workspaces.map((workspace) => (_jsx("option", { value: workspace.uid, children: workspace.name }, workspace.uid))), _jsx("option", { value: NEW_WORKSPACE, children: "+ New workspace\u2026" })] }), SECTIONS.map(({ id, label, path, icon: Icon }) => (_jsxs("a", { href: context.href(path), "aria-current": id === section ? "page" : undefined, className: `flex items-center gap-2 rounded-sm px-2 py-1.5 text-sm ${id === section ? "bg-primary-lightest text-primary-dark font-semibold" : "text-text hover:bg-surface-alt"}`, children: [_jsx(Icon, { "aria-hidden": true, className: "w-4 h-4" }), label] }, id)))] })), _jsxs("main", { className: "flex-1 min-w-0 overflow-y-auto p-6", children: [error && _jsx(Alert, { children: error }), !error && workspaces === null && _jsx("p", { className: "text-sm text-text-muted", children: "Loading\u2026" }), workspaces !== null && !context && _jsx(CreateFirstWorkspace, { onCreated: (workspace) => switchTo(workspace.uid) }), _jsx(Modal, { open: creating, onClose: () => setCreating(false), title: "New workspace", children: _jsx(CreateWorkspaceForm, { onCreated: (workspace) => switchTo(workspace.uid) }) }), context && _jsx(CrmContext.Provider, { value: context, children: children })] })] }) }));
|
|
109
114
|
}
|
|
110
115
|
/** The form a caller with no workspace sees. */
|
|
111
116
|
export function CreateFirstWorkspace({ onCreated }) {
|
|
117
|
+
return (_jsxs("div", { className: "max-w-md", children: [_jsx("h1", { className: "text-lg font-bold tracking-tight mb-2", children: "Create your CRM workspace" }), _jsx("p", { className: "text-sm text-text-muted mb-4", children: "A workspace holds your team's contacts, companies and tasks. You can invite colleagues to it once it exists." }), _jsx(CreateWorkspaceForm, { onCreated: onCreated })] }));
|
|
118
|
+
}
|
|
119
|
+
/** Names and creates a workspace (in the browser's time zone - changeable in its settings), then hands it to `onCreated`. */
|
|
120
|
+
export function CreateWorkspaceForm({ onCreated }) {
|
|
112
121
|
const [name, setName] = useState("");
|
|
113
122
|
const [error, setError] = useState(null);
|
|
114
123
|
const [saving, setSaving] = useState(false);
|
|
@@ -123,5 +132,5 @@ export function CreateFirstWorkspace({ onCreated }) {
|
|
|
123
132
|
setSaving(false);
|
|
124
133
|
}
|
|
125
134
|
}
|
|
126
|
-
return (_jsxs("form", { onSubmit: submit, className: "
|
|
135
|
+
return (_jsxs("form", { onSubmit: submit, className: "min-w-[20rem]", children: [error && _jsx(Alert, { children: error }), _jsx(FormField, { label: "Name", htmlFor: "crm-new-workspace", children: _jsx("input", { id: "crm-new-workspace", className: INPUT_CLASS, value: name, onChange: (event) => setName(event.target.value), required: true }) }), _jsx(Button, { type: "submit", loading: saving, disabled: saving || name.trim().length === 0, className: "!w-auto mt-3", children: "Create workspace" })] }));
|
|
127
136
|
}
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
+
import { RecipientSuggestion } from "@rapidmx/web-client/lib/mail/directoryApi.js";
|
|
2
3
|
/**
|
|
3
4
|
* A workspace's settings: its details, members and their roles, the addresses it sends as, and its custom properties - changeable by
|
|
4
5
|
* its admins and owners (everyone else sees them read-only) - and, for owners, deleting it.
|
|
5
6
|
*/
|
|
6
7
|
export default function WorkspaceSettings(): React.JSX.Element;
|
|
8
|
+
/** The address of an entry of the people field: `Name <address>` or a bare address. */
|
|
9
|
+
export declare function chipAddress(chip: string): string;
|
|
10
|
+
/** Suggests only people with an account on this server - the only ones who can be members. */
|
|
11
|
+
export declare function suggestPeople(query: string, options: {
|
|
12
|
+
limit?: number;
|
|
13
|
+
signal?: AbortSignal;
|
|
14
|
+
}): Promise<RecipientSuggestion[]>;
|
|
@@ -3,11 +3,16 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
// Copyright (C) 2026 Jean-Philippe Steinmetz
|
|
4
4
|
// SPDX-License-Identifier: MPL-2.0
|
|
5
5
|
///////////////////////////////////////////////////////////////////////////////
|
|
6
|
-
import { useEffect, useState } from "react";
|
|
6
|
+
import { useEffect, useMemo, useState } from "react";
|
|
7
7
|
import Alert from "@rapidmx/web-client/lib/components/feedback/Alert.js";
|
|
8
8
|
import Button from "@rapidmx/web-client/lib/components/buttons/Button.js";
|
|
9
9
|
import FormField from "@rapidmx/web-client/lib/components/forms/FormField.js";
|
|
10
|
-
import
|
|
10
|
+
import TimeZonePicker from "@rapidmx/web-client/lib/components/pickers/TimeZonePicker.js";
|
|
11
|
+
import { timeZoneOptions } from "@rapidmx/web-client/lib/util/timeZone.js";
|
|
12
|
+
import { listMailboxes } from "@rapidmx/web-client/lib/mail/mailApi.js";
|
|
13
|
+
import { searchDirectory } from "@rapidmx/web-client/lib/mail/directoryApi.js";
|
|
14
|
+
import RecipientInput from "@rapidmx/web-client/shared/components/mail/compose/RecipientInput.js";
|
|
15
|
+
import { addMember, addSender, createProperty, createSuppression, deleteSuppression, listSuppressions, deleteProperty, deleteWorkspace, errorMessage, listMembers, listProperties, listSenders, removeMember, removeSender, sendableMailboxes, updateMember, updateWorkspace, updateSender, } from "../crmApi.js";
|
|
11
16
|
import { INPUT_CLASS, WORKSPACE_STORAGE_KEY, useCrm } from "./CrmShell.js";
|
|
12
17
|
const ROLES = [
|
|
13
18
|
{ value: "owner", label: "Owner" },
|
|
@@ -57,18 +62,29 @@ function Details() {
|
|
|
57
62
|
const fields = [
|
|
58
63
|
["name", "Name"],
|
|
59
64
|
["description", "Description"],
|
|
60
|
-
["timezone", "Time zone"],
|
|
61
65
|
["postalAddress", "Postal address (shown in marketing email footers)"],
|
|
62
66
|
["website", "Website"],
|
|
63
67
|
];
|
|
64
|
-
|
|
68
|
+
const zones = useMemo(() => timeZoneOptions(workspace.timezone), [workspace.timezone]);
|
|
69
|
+
return (_jsxs("form", { onSubmit: save, className: "flex flex-col gap-3", "aria-label": "Workspace details", children: [_jsx("h2", { className: "text-sm font-semibold uppercase tracking-wide text-text-muted", children: "Workspace" }), error && _jsx(Alert, { children: error }), message && _jsx("p", { className: "text-sm text-success", children: message }), fields.map(([field, label]) => (_jsx(FormField, { label: label, htmlFor: `workspace-${field}`, children: _jsx("input", { id: `workspace-${field}`, className: INPUT_CLASS, value: values[field], disabled: !canManage, onChange: (event) => setValues((current) => ({ ...current, [field]: event.target.value })) }) }, field))), _jsx(FormField, { label: "Time zone", htmlFor: "workspace-timezone", children: canManage ? (_jsx(TimeZonePicker, { id: "workspace-timezone", value: values.timezone, zones: zones, onChange: (timezone) => setValues((current) => ({ ...current, timezone })) })) : (_jsx("input", { id: "workspace-timezone", className: INPUT_CLASS, value: values.timezone, disabled: true })) }), canManage && (_jsx(Button, { type: "submit", className: "!w-auto self-start", children: "Save" }))] }));
|
|
70
|
+
}
|
|
71
|
+
/** The address of an entry of the people field: `Name <address>` or a bare address. */
|
|
72
|
+
export function chipAddress(chip) {
|
|
73
|
+
const match = /<([^<>]+)>\s*$/.exec(chip);
|
|
74
|
+
return (match ? match[1] : chip).trim().toLowerCase();
|
|
75
|
+
}
|
|
76
|
+
/** Suggests only people with an account on this server - the only ones who can be members. */
|
|
77
|
+
export async function suggestPeople(query, options) {
|
|
78
|
+
return (await searchDirectory(query, options)).filter((suggestion) => suggestion.kind === "user");
|
|
65
79
|
}
|
|
66
80
|
function Members() {
|
|
67
81
|
const { workspace, canManage } = useCrm();
|
|
68
82
|
const [members, setMembers] = useState([]);
|
|
69
|
-
const [
|
|
83
|
+
const [text, setText] = useState("");
|
|
84
|
+
const [people, setPeople] = useState({ chips: [], pending: "" });
|
|
70
85
|
const [role, setRole] = useState("editor");
|
|
71
86
|
const [error, setError] = useState(null);
|
|
87
|
+
const [adding, setAdding] = useState(false);
|
|
72
88
|
async function load() {
|
|
73
89
|
setMembers(await listMembers(workspace.uid));
|
|
74
90
|
}
|
|
@@ -85,18 +101,44 @@ function Members() {
|
|
|
85
101
|
setError(errorMessage(err, failure));
|
|
86
102
|
}
|
|
87
103
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
104
|
+
/** Adds everyone in the field; those that fail stay in it, with why. */
|
|
105
|
+
async function add(event) {
|
|
106
|
+
event.preventDefault();
|
|
107
|
+
const entries = [...people.chips, ...(people.pending.trim() ? [people.pending.trim()] : [])];
|
|
108
|
+
setAdding(true);
|
|
109
|
+
const failed = [];
|
|
110
|
+
const reasons = [];
|
|
111
|
+
for (const entry of entries) {
|
|
112
|
+
try {
|
|
113
|
+
await addMember(workspace.uid, { address: chipAddress(entry), role });
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
failed.push(entry);
|
|
117
|
+
reasons.push(`${chipAddress(entry)}: ${errorMessage(err, "could not be added.")}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
setText(failed.join(", "));
|
|
121
|
+
setPeople({ chips: failed, pending: "" });
|
|
122
|
+
setAdding(false);
|
|
123
|
+
try {
|
|
124
|
+
await load();
|
|
125
|
+
setError(reasons.length > 0 ? reasons.join(" ") : null);
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
setError([...reasons, errorMessage(err, "Could not load the members.")].join(" "));
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
const count = people.chips.length + (people.pending.trim() ? 1 : 0);
|
|
132
|
+
return (_jsxs("section", { "aria-label": "Members", className: "flex flex-col gap-3", children: [_jsx("h2", { className: "text-sm font-semibold uppercase tracking-wide text-text-muted", children: "Members" }), error && _jsx(Alert, { children: error }), _jsx("ul", { className: "flex flex-col divide-y divide-border border-y border-border", children: members.map((member) => {
|
|
133
|
+
const name = member.displayName || member.address || member.userUid;
|
|
134
|
+
return (_jsxs("li", { className: "flex items-center gap-3 py-2 text-sm", children: [_jsxs("span", { className: "flex-1 min-w-0", children: [_jsx("span", { className: "block truncate", children: name }), member.displayName && member.address && _jsx("span", { className: "block truncate text-xs text-text-muted", children: member.address })] }), canManage ? (_jsx("select", { "aria-label": `Role of ${name}`, className: `${INPUT_CLASS} !w-32`, value: member.role, onChange: (event) => void act(() => updateMember(workspace.uid, member.userUid, event.target.value), "Could not change the role."), children: ROLES.map((entry) => (_jsx("option", { value: entry.value, children: entry.label }, entry.value))) })) : (_jsx("span", { className: "text-text-muted", children: member.role })), canManage && (_jsx("button", { type: "button", className: "text-xs text-text-muted hover:text-danger", onClick: () => void act(() => removeMember(workspace.uid, member.userUid), "Could not remove the member."), children: "Remove" }))] }, member.userUid));
|
|
135
|
+
}) }), canManage && (_jsxs("form", { className: "flex flex-wrap items-start gap-2", "aria-label": "Add members", onSubmit: (event) => void add(event), children: [_jsx("div", { className: "flex-1 min-w-[18rem]", children: _jsx(RecipientInput, { id: "crm-new-members", label: "People", ariaLabel: "People to add", placeholder: "Search people by name or address", value: text, onChange: setText, onEdit: (chips, pending) => setPeople({ chips, pending }), fetchSuggestions: suggestPeople, className: INPUT_CLASS }) }), _jsx("select", { "aria-label": "New member role", className: `${INPUT_CLASS} !w-32`, value: role, onChange: (event) => setRole(event.target.value), children: ROLES.map((entry) => (_jsx("option", { value: entry.value, children: entry.label }, entry.value))) }), _jsx(Button, { type: "submit", variant: "secondary", loading: adding, disabled: adding || count === 0, className: "!w-auto", children: count > 1 ? `Add ${count} members` : "Add member" })] }))] }));
|
|
95
136
|
}
|
|
96
137
|
function Senders() {
|
|
97
138
|
const { workspace, canManage } = useCrm();
|
|
98
139
|
const [senders, setSenders] = useState([]);
|
|
99
|
-
const [
|
|
140
|
+
const [mailboxes, setMailboxes] = useState(null);
|
|
141
|
+
const [mailboxUid, setMailboxUid] = useState("");
|
|
100
142
|
const [fromName, setFromName] = useState("");
|
|
101
143
|
const [error, setError] = useState(null);
|
|
102
144
|
async function load() {
|
|
@@ -105,11 +147,22 @@ function Senders() {
|
|
|
105
147
|
useEffect(() => {
|
|
106
148
|
load().catch((err) => setError(errorMessage(err, "Could not load the senders.")));
|
|
107
149
|
}, [workspace.uid]);
|
|
150
|
+
useEffect(() => {
|
|
151
|
+
if (!canManage) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
(async () => {
|
|
155
|
+
const own = await listMailboxes({ limit: 200 });
|
|
156
|
+
setMailboxes(own.length > 0 ? await sendableMailboxes(workspace.uid, own.map((mailbox) => mailbox.uid)) : []);
|
|
157
|
+
})().catch(() => setMailboxes([]));
|
|
158
|
+
}, [workspace.uid, canManage]);
|
|
159
|
+
const choices = (mailboxes ?? []).filter((mailbox) => !senders.some((sender) => sender.fromAddress === mailbox.address));
|
|
160
|
+
const chosen = choices.find((mailbox) => mailbox.uid === mailboxUid);
|
|
108
161
|
async function add(event) {
|
|
109
162
|
event.preventDefault();
|
|
110
163
|
try {
|
|
111
|
-
await addSender(workspace.uid, { fromAddress, ...(fromName.trim() ? { fromName } : {}) });
|
|
112
|
-
|
|
164
|
+
await addSender(workspace.uid, { fromAddress: chosen.address, ...(fromName.trim() ? { fromName: fromName.trim() } : {}) });
|
|
165
|
+
setMailboxUid("");
|
|
113
166
|
setFromName("");
|
|
114
167
|
setError(null);
|
|
115
168
|
await load();
|
|
@@ -118,7 +171,7 @@ function Senders() {
|
|
|
118
171
|
setError(errorMessage(err, "Could not add the sender."));
|
|
119
172
|
}
|
|
120
173
|
}
|
|
121
|
-
return (_jsxs("section", { "aria-label": "Senders", className: "flex flex-col gap-3", children: [_jsx("h2", { className: "text-sm font-semibold uppercase tracking-wide text-text-muted", children: "Send as" }), _jsx("p", { className: "text-sm text-text-muted", children: "
|
|
174
|
+
return (_jsxs("section", { "aria-label": "Senders", className: "flex flex-col gap-3", children: [_jsx("h2", { className: "text-sm font-semibold uppercase tracking-wide text-text-muted", children: "Send as" }), _jsx("p", { className: "text-sm text-text-muted", children: "Mailboxes the CRM sends from. Replies to mail sent from the CRM arrive in these mailboxes." }), error && _jsx(Alert, { children: error }), _jsx("ul", { className: "flex flex-col gap-1", children: senders.map((sender) => (_jsxs("li", { className: "flex items-center gap-3 text-sm", children: [_jsxs("span", { className: "flex-1", children: [sender.fromName, " <", sender.fromAddress, ">"] }), _jsxs("label", { className: "flex items-center gap-1 text-xs text-text-muted", title: "Mail this mailbox exchanges with contacts goes on their timelines", children: [_jsx("input", { type: "checkbox", disabled: !canManage, checked: !!sender.logEmail, onChange: async (event) => {
|
|
122
175
|
try {
|
|
123
176
|
await updateSender(workspace.uid, sender.uid, { logEmail: event.target.checked });
|
|
124
177
|
}
|
|
@@ -129,7 +182,10 @@ function Senders() {
|
|
|
129
182
|
} }), "Log email with contacts"] }), canManage && (_jsx("button", { type: "button", className: "text-xs text-text-muted hover:text-danger", onClick: async () => {
|
|
130
183
|
await removeSender(workspace.uid, sender.uid);
|
|
131
184
|
await load();
|
|
132
|
-
}, children: "Remove" }))] }, sender.uid))) }), canManage && (
|
|
185
|
+
}, children: "Remove" }))] }, sender.uid))) }), canManage && mailboxes !== null && mailboxes.length === 0 && (_jsx("p", { className: "text-sm text-text-muted", children: "You have no mailbox you can send from. Its owner can add it, or give you send access to it." })), canManage && choices.length > 0 && (_jsxs("form", { className: "flex flex-wrap gap-2", "aria-label": "Add sender", onSubmit: (event) => void add(event), children: [_jsxs("select", { "aria-label": "Mailbox", className: `${INPUT_CLASS} !w-72`, value: mailboxUid, onChange: (event) => {
|
|
186
|
+
setMailboxUid(event.target.value);
|
|
187
|
+
setFromName(choices.find((mailbox) => mailbox.uid === event.target.value)?.displayName ?? "");
|
|
188
|
+
}, children: [_jsx("option", { value: "", children: "Choose a mailbox\u2026" }), choices.map((mailbox) => (_jsx("option", { value: mailbox.uid, children: mailbox.displayName ? `${mailbox.displayName} <${mailbox.address}>` : mailbox.address }, mailbox.uid)))] }), _jsx("input", { "aria-label": "Sender name", placeholder: "Name shown to recipients", className: `${INPUT_CLASS} !w-56`, value: fromName, onChange: (event) => setFromName(event.target.value) }), _jsx(Button, { type: "submit", variant: "secondary", disabled: !chosen, className: "!w-auto", children: "Add sender" })] }))] }));
|
|
133
189
|
}
|
|
134
190
|
function Properties() {
|
|
135
191
|
const { workspace, canManage } = useCrm();
|
|
@@ -188,6 +188,14 @@ export declare const addSender: (uid: string, input: {
|
|
|
188
188
|
replyToAddress?: string;
|
|
189
189
|
logEmail?: boolean;
|
|
190
190
|
}) => Promise<WorkspaceSender>;
|
|
191
|
+
/** A mailbox the caller may add as a sender. */
|
|
192
|
+
export interface SendableMailbox {
|
|
193
|
+
uid: string;
|
|
194
|
+
address: string;
|
|
195
|
+
displayName: string;
|
|
196
|
+
}
|
|
197
|
+
/** Which of `mailboxUids` (the caller's mailboxes) the caller can send from, for the "Send as" picker. */
|
|
198
|
+
export declare const sendableMailboxes: (uid: string, mailboxUids: string[]) => Promise<SendableMailbox[]>;
|
|
191
199
|
export declare const removeSender: (uid: string, senderUid: string) => Promise<void>;
|
|
192
200
|
export declare function searchRecords<T extends CrmRecord>(objectType: CrmObjectType, workspaceUid: string, request: SearchRequest): Promise<SearchResult<T>>;
|
|
193
201
|
export declare function getRecord<T extends CrmRecord>(objectType: CrmObjectType, workspaceUid: string, uid: string): Promise<T>;
|
|
@@ -26,6 +26,8 @@ export const removeMember = (uid, userUid) => apiFetch(`/mail/crm/workspaces/${e
|
|
|
26
26
|
export const listSenders = (uid) => apiFetch(`/mail/crm/workspaces/${enc(uid)}/senders`);
|
|
27
27
|
export const updateSender = (uid, senderUid, input) => apiFetch(`/mail/crm/workspaces/${enc(uid)}/senders/${enc(senderUid)}`, json("PUT", input));
|
|
28
28
|
export const addSender = (uid, input) => apiFetch(`/mail/crm/workspaces/${enc(uid)}/senders`, json("POST", input));
|
|
29
|
+
/** Which of `mailboxUids` (the caller's mailboxes) the caller can send from, for the "Send as" picker. */
|
|
30
|
+
export const sendableMailboxes = (uid, mailboxUids) => apiFetch(`/mail/crm/workspaces/${enc(uid)}/sendable-mailboxes`, json("POST", { mailboxUids }));
|
|
29
31
|
export const removeSender = (uid, senderUid) => apiFetch(`/mail/crm/workspaces/${enc(uid)}/senders/${enc(senderUid)}`, json("DELETE"));
|
|
30
32
|
// Contacts and companies
|
|
31
33
|
export function searchRecords(objectType, workspaceUid, request) {
|
|
@@ -63,6 +63,8 @@ const WORKSPACE_DATA = [
|
|
|
63
63
|
"workspaceSender",
|
|
64
64
|
"workspaceMember",
|
|
65
65
|
];
|
|
66
|
+
/** How many mailboxes one "Send as" check may name. */
|
|
67
|
+
export const MAX_SENDABLE_CHECK = 200;
|
|
66
68
|
/**
|
|
67
69
|
* CRM workspaces (`/api/mail/crm/workspaces`): creating one (the creator becomes its owner), listing the caller's, changing and deleting
|
|
68
70
|
* them, and managing who is a member with which role, and which addresses the workspace sends as.
|
|
@@ -115,7 +117,7 @@ export class BaseWorkspaceRoute extends CrmRouteBase {
|
|
|
115
117
|
acl: { uid: instance.uid, records: [memberRecord(userUid, WorkspaceRole.OWNER)] },
|
|
116
118
|
});
|
|
117
119
|
const memberClass = this.classes.workspaceMember;
|
|
118
|
-
await (await this.repo("workspaceMember")).create(new memberClass({ workspaceUid: workspace.uid, userUid, role: WorkspaceRole.OWNER }), {
|
|
120
|
+
await (await this.repo("workspaceMember")).create(new memberClass({ workspaceUid: workspace.uid, userUid, role: WorkspaceRole.OWNER, ...(await this.describeUser(userUid)) }), {
|
|
119
121
|
ignoreACL: true,
|
|
120
122
|
});
|
|
121
123
|
return { ...this.plain(workspace), role: WorkspaceRole.OWNER };
|
|
@@ -148,7 +150,12 @@ export class BaseWorkspaceRoute extends CrmRouteBase {
|
|
|
148
150
|
}
|
|
149
151
|
async listMembers(workspaceUid, user) {
|
|
150
152
|
await this.requireAccess(user, workspaceUid, WorkspaceAction.READ);
|
|
151
|
-
|
|
153
|
+
const views = [];
|
|
154
|
+
for (const member of await this.members(workspaceUid)) {
|
|
155
|
+
const view = this.plain(member);
|
|
156
|
+
views.push(view.address ? view : { ...view, ...(await this.describeUser(member.userUid)) });
|
|
157
|
+
}
|
|
158
|
+
return views;
|
|
152
159
|
}
|
|
153
160
|
/**
|
|
154
161
|
* Adds a member by `userUid`, or by `address` - resolved to the owner of the mailbox with that address, so a colleague can be
|
|
@@ -248,6 +255,26 @@ export class BaseWorkspaceRoute extends CrmRouteBase {
|
|
|
248
255
|
this.notify(workspaceUid, "WorkspaceSender", "create", this.plain(sender));
|
|
249
256
|
return this.plain(sender);
|
|
250
257
|
}
|
|
258
|
+
/**
|
|
259
|
+
* Which of `mailboxUids` (the caller's mailboxes, as the web client lists them) the caller may add as senders - those they can
|
|
260
|
+
* send from (update access) - with each one's address and name, for the "Send as" picker. Up to `MAX_SENDABLE_CHECK` at once.
|
|
261
|
+
*/
|
|
262
|
+
async sendableMailboxes(workspaceUid, body, user) {
|
|
263
|
+
await this.requireAccess(user, workspaceUid, WorkspaceAction.MANAGE);
|
|
264
|
+
const uids = requireObject(body).mailboxUids;
|
|
265
|
+
if (!Array.isArray(uids) || uids.length > MAX_SENDABLE_CHECK || uids.some((uid) => typeof uid !== "string" || uid.length === 0 || uid.length > 128)) {
|
|
266
|
+
throw badRequest(`'mailboxUids' must be a list of up to ${MAX_SENDABLE_CHECK} mailbox uids.`);
|
|
267
|
+
}
|
|
268
|
+
const repo = await this.repo("mailbox");
|
|
269
|
+
const sendable = [];
|
|
270
|
+
for (const uid of new Set(uids)) {
|
|
271
|
+
const mailbox = await repo.findOne(uid, { ignoreACL: true, skipCache: true });
|
|
272
|
+
if (mailbox && (await hasMailAccess(this.aclUtils, this.trustedRoles, user, mailbox.uid, ACLAction.UPDATE))) {
|
|
273
|
+
sendable.push({ uid: mailbox.uid, address: mailbox.primarySmtpAddress, displayName: mailbox.displayName ?? "" });
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return sendable;
|
|
277
|
+
}
|
|
251
278
|
async updateSender(workspaceUid, senderUid, body, user) {
|
|
252
279
|
await this.requireAccess(user, workspaceUid, WorkspaceAction.MANAGE);
|
|
253
280
|
const sender = await this.requireWorkspaceSender(workspaceUid, senderUid);
|
|
@@ -320,7 +347,8 @@ export class BaseWorkspaceRoute extends CrmRouteBase {
|
|
|
320
347
|
/** Who a member request names: `userUid` as given, or `address` as the owner of the mailbox with that address. */
|
|
321
348
|
async resolvePerson(body) {
|
|
322
349
|
if (typeof body.userUid === "string" && body.userUid.trim().length > 0 && body.userUid.length <= 128) {
|
|
323
|
-
|
|
350
|
+
const userUid = body.userUid.trim().toLowerCase();
|
|
351
|
+
return { userUid, ...(await this.describeUser(userUid)) };
|
|
324
352
|
}
|
|
325
353
|
const address = readEmail(body, "address");
|
|
326
354
|
if (!address) {
|
|
@@ -340,6 +368,14 @@ export class BaseWorkspaceRoute extends CrmRouteBase {
|
|
|
340
368
|
const matches = await (await this.repo("mailbox")).find({ primarySmtpAddress: ModelUtils.literal(address) }, { ignoreACL: true, limit: 1, skipCache: true });
|
|
341
369
|
return matches[0];
|
|
342
370
|
}
|
|
371
|
+
/**
|
|
372
|
+
* A user's name and address, as their own mailbox (the first they own) has them - users are known to the mail server only by
|
|
373
|
+
* uid. Nothing for a user without a mailbox.
|
|
374
|
+
*/
|
|
375
|
+
async describeUser(userUid) {
|
|
376
|
+
const owned = (await (await this.repo("mailbox")).find({ ownerUserUid: ModelUtils.literal(userUid), sort: { dateCreated: "ASC" } }, { ignoreACL: true, limit: 1, skipCache: true }))[0];
|
|
377
|
+
return owned ? { address: owned.primarySmtpAddress, ...(owned.displayName ? { displayName: owned.displayName } : {}) } : {};
|
|
378
|
+
}
|
|
343
379
|
/** The mailbox `address` belongs to, when the caller may send from it (update access to the mailbox), else a 400. */
|
|
344
380
|
async requireSendableMailbox(user, address) {
|
|
345
381
|
const mailbox = await this.findMailboxByAddress(address);
|
|
@@ -509,6 +545,14 @@ __decorate([
|
|
|
509
545
|
__metadata("design:paramtypes", [String, Object, Object]),
|
|
510
546
|
__metadata("design:returntype", Promise)
|
|
511
547
|
], BaseWorkspaceRoute.prototype, "addSender", null);
|
|
548
|
+
__decorate([
|
|
549
|
+
Post("/:workspaceUid/sendable-mailboxes"),
|
|
550
|
+
__param(0, Param("workspaceUid")),
|
|
551
|
+
__param(2, AuthUser),
|
|
552
|
+
__metadata("design:type", Function),
|
|
553
|
+
__metadata("design:paramtypes", [String, Object, Object]),
|
|
554
|
+
__metadata("design:returntype", Promise)
|
|
555
|
+
], BaseWorkspaceRoute.prototype, "sendableMailboxes", null);
|
|
512
556
|
__decorate([
|
|
513
557
|
Put("/:workspaceUid/senders/:senderUid"),
|
|
514
558
|
__param(0, Param("workspaceUid")),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BaseWorkspaceRoute.js","sourceRoot":"","sources":["../../../src/routes/BaseWorkspaceRoute.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"BaseWorkspaceRoute.js","sourceRoot":"","sources":["../../../src/routes/BaseWorkspaceRoute.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,14 @@ import { CrmRouteBase } from "./CrmRouteBase.js";
|
|
|
4
4
|
/** How many members and senders one workspace may have, by default (`mail:crm:max_members`, `mail:crm:max_senders`). */
|
|
5
5
|
export declare const MAX_MEMBERS = 500;
|
|
6
6
|
export declare const MAX_SENDERS = 50;
|
|
7
|
+
/** How many mailboxes one "Send as" check may name. */
|
|
8
|
+
export declare const MAX_SENDABLE_CHECK = 200;
|
|
9
|
+
/** A mailbox the caller may add as a sender. */
|
|
10
|
+
export interface SendableMailbox {
|
|
11
|
+
uid: string;
|
|
12
|
+
address: string;
|
|
13
|
+
displayName: string;
|
|
14
|
+
}
|
|
7
15
|
/** A workspace as its members see it: the record plus the caller's own role. */
|
|
8
16
|
export interface WorkspaceView extends Workspace {
|
|
9
17
|
role: WorkspaceRole;
|
|
@@ -45,6 +53,11 @@ export declare abstract class BaseWorkspaceRoute extends CrmRouteBase {
|
|
|
45
53
|
* mailbox's primary address or one of its aliases.
|
|
46
54
|
*/
|
|
47
55
|
addSender(workspaceUid: string, body: unknown, user?: JWTUser): Promise<WorkspaceSender>;
|
|
56
|
+
/**
|
|
57
|
+
* Which of `mailboxUids` (the caller's mailboxes, as the web client lists them) the caller may add as senders - those they can
|
|
58
|
+
* send from (update access) - with each one's address and name, for the "Send as" picker. Up to `MAX_SENDABLE_CHECK` at once.
|
|
59
|
+
*/
|
|
60
|
+
sendableMailboxes(workspaceUid: string, body: unknown, user?: JWTUser): Promise<SendableMailbox[]>;
|
|
48
61
|
updateSender(workspaceUid: string, senderUid: string, body: unknown, user?: JWTUser): Promise<WorkspaceSender>;
|
|
49
62
|
removeSender(workspaceUid: string, senderUid: string, user?: JWTUser): Promise<void>;
|
|
50
63
|
/** The caller's uid, lowercased, or a 401 for an anonymous caller. */
|
|
@@ -61,6 +74,11 @@ export declare abstract class BaseWorkspaceRoute extends CrmRouteBase {
|
|
|
61
74
|
* mailbox's own address, so an alias never silently picks some other mailbox.
|
|
62
75
|
*/
|
|
63
76
|
private findMailboxByAddress;
|
|
77
|
+
/**
|
|
78
|
+
* A user's name and address, as their own mailbox (the first they own) has them - users are known to the mail server only by
|
|
79
|
+
* uid. Nothing for a user without a mailbox.
|
|
80
|
+
*/
|
|
81
|
+
private describeUser;
|
|
64
82
|
/** The mailbox `address` belongs to, when the caller may send from it (update access to the mailbox), else a 400. */
|
|
65
83
|
private requireSendableMailbox;
|
|
66
84
|
private requireWorkspace;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rapidmx/crm-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "RapidMX plugin that provides a customer relationship management and marketing platform: contacts, companies, mailing lists, campaigns, automations and sales pipelines.",
|
|
5
5
|
"repository": "https://github.com/rapidmx/crm-plugin.git",
|
|
6
6
|
"author": "RapidREST <rapidrests@gmail.com>",
|