Seth commited on
Commit ·
2ba39f6
1
Parent(s): bdec327
update
Browse files
frontend/src/components/campaigns/CampaignSequenceBuilder.jsx
CHANGED
|
@@ -196,11 +196,13 @@ function WaitCard({ step, onRemove, onDaysChange }) {
|
|
| 196 |
);
|
| 197 |
}
|
| 198 |
|
| 199 |
-
function ActionCard({ step, onRemove, senderHint, accountHint }) {
|
| 200 |
const sender = (senderHint || '').trim();
|
| 201 |
const account = (accountHint || '').trim();
|
| 202 |
const showSender = sender && (!account || sender !== account);
|
| 203 |
const showLiMeta = step.channel === 'linkedin' && (showSender || account);
|
|
|
|
|
|
|
| 204 |
return (
|
| 205 |
<div className="relative w-full max-w-md">
|
| 206 |
<div className="flex w-full items-center gap-3 rounded-xl border border-slate-200 bg-white px-4 py-3 text-left shadow-sm">
|
|
@@ -222,6 +224,9 @@ function ActionCard({ step, onRemove, senderHint, accountHint }) {
|
|
| 222 |
{account ? <span>Profile: {account}</span> : null}
|
| 223 |
</p>
|
| 224 |
) : null}
|
|
|
|
|
|
|
|
|
|
| 225 |
</div>
|
| 226 |
<ChevronRight className="h-5 w-5 shrink-0 text-slate-300" aria-hidden />
|
| 227 |
</div>
|
|
@@ -245,7 +250,7 @@ function ActionCard({ step, onRemove, senderHint, accountHint }) {
|
|
| 245 |
/**
|
| 246 |
* Vertical sequence builder: START → steps (+ inserts) → END with dashed spine.
|
| 247 |
*/
|
| 248 |
-
export default function CampaignSequenceBuilder({ value, onChange, linkedinDefaults }) {
|
| 249 |
const steps = value;
|
| 250 |
const setSteps = onChange;
|
| 251 |
const [pickerIndex, setPickerIndex] = useState(null);
|
|
@@ -260,6 +265,14 @@ export default function CampaignSequenceBuilder({ value, onChange, linkedinDefau
|
|
| 260 |
},
|
| 261 |
[linkedinDefaults]
|
| 262 |
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 263 |
|
| 264 |
const insertAt = useCallback(
|
| 265 |
(index, kind) => {
|
|
@@ -388,6 +401,17 @@ export default function CampaignSequenceBuilder({ value, onChange, linkedinDefau
|
|
| 388 |
)
|
| 389 |
: ''
|
| 390 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 391 |
onRemove={() => removeAt(index)}
|
| 392 |
/>
|
| 393 |
)}
|
|
|
|
| 196 |
);
|
| 197 |
}
|
| 198 |
|
| 199 |
+
function ActionCard({ step, onRemove, senderHint, accountHint, emailAccountHint }) {
|
| 200 |
const sender = (senderHint || '').trim();
|
| 201 |
const account = (accountHint || '').trim();
|
| 202 |
const showSender = sender && (!account || sender !== account);
|
| 203 |
const showLiMeta = step.channel === 'linkedin' && (showSender || account);
|
| 204 |
+
const mailbox = (emailAccountHint || '').trim();
|
| 205 |
+
const showEmailMeta = step.channel === 'gmail' && !!mailbox;
|
| 206 |
return (
|
| 207 |
<div className="relative w-full max-w-md">
|
| 208 |
<div className="flex w-full items-center gap-3 rounded-xl border border-slate-200 bg-white px-4 py-3 text-left shadow-sm">
|
|
|
|
| 224 |
{account ? <span>Profile: {account}</span> : null}
|
| 225 |
</p>
|
| 226 |
) : null}
|
| 227 |
+
{showEmailMeta ? (
|
| 228 |
+
<p className="mt-1 text-[11px] leading-snug text-violet-700">Mailbox: {mailbox}</p>
|
| 229 |
+
) : null}
|
| 230 |
</div>
|
| 231 |
<ChevronRight className="h-5 w-5 shrink-0 text-slate-300" aria-hidden />
|
| 232 |
</div>
|
|
|
|
| 250 |
/**
|
| 251 |
* Vertical sequence builder: START → steps (+ inserts) → END with dashed spine.
|
| 252 |
*/
|
| 253 |
+
export default function CampaignSequenceBuilder({ value, onChange, linkedinDefaults, mailboxDefaults }) {
|
| 254 |
const steps = value;
|
| 255 |
const setSteps = onChange;
|
| 256 |
const [pickerIndex, setPickerIndex] = useState(null);
|
|
|
|
| 265 |
},
|
| 266 |
[linkedinDefaults]
|
| 267 |
);
|
| 268 |
+
const mailboxLabelFor = useCallback(
|
| 269 |
+
(refId) => {
|
| 270 |
+
if (refId == null) return '';
|
| 271 |
+
const a = mailboxDefaults?.accounts?.find((x) => Number(x.id) === Number(refId));
|
| 272 |
+
return (a?.display_name || a?.label || '').trim();
|
| 273 |
+
},
|
| 274 |
+
[mailboxDefaults]
|
| 275 |
+
);
|
| 276 |
|
| 277 |
const insertAt = useCallback(
|
| 278 |
(index, kind) => {
|
|
|
|
| 401 |
)
|
| 402 |
: ''
|
| 403 |
}
|
| 404 |
+
emailAccountHint={
|
| 405 |
+
step.channel === 'gmail'
|
| 406 |
+
? (
|
| 407 |
+
mailboxLabelFor(
|
| 408 |
+
step.unipile_account_ref_id ??
|
| 409 |
+
mailboxDefaults?.default_mailbox_unipile_account_ref_id
|
| 410 |
+
) ||
|
| 411 |
+
(mailboxDefaults?.mailbox_profile_display_name || '').trim()
|
| 412 |
+
)
|
| 413 |
+
: ''
|
| 414 |
+
}
|
| 415 |
onRemove={() => removeAt(index)}
|
| 416 |
/>
|
| 417 |
)}
|
frontend/src/components/campaigns/CreateCampaignWizard.jsx
CHANGED
|
@@ -36,6 +36,7 @@ export default function CreateCampaignWizard({ open, onOpenChange, onComplete })
|
|
| 36 |
const [estimatedContacts, setEstimatedContacts] = useState(0);
|
| 37 |
const [sequenceSteps, setSequenceSteps] = useState(() => createDefaultSequenceSteps());
|
| 38 |
const [linkedinDefaults, setLinkedinDefaults] = useState(null);
|
|
|
|
| 39 |
|
| 40 |
const reset = useCallback(() => {
|
| 41 |
setStep(1);
|
|
@@ -76,23 +77,34 @@ export default function CreateCampaignWizard({ open, onOpenChange, onComplete })
|
|
| 76 |
useEffect(() => {
|
| 77 |
if (!open) {
|
| 78 |
setLinkedinDefaults(null);
|
|
|
|
| 79 |
return;
|
| 80 |
}
|
| 81 |
let cancelled = false;
|
| 82 |
-
|
| 83 |
-
.then((r) => r.json())
|
| 84 |
-
.then((
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 96 |
return () => {
|
| 97 |
cancelled = true;
|
| 98 |
};
|
|
@@ -301,6 +313,7 @@ export default function CreateCampaignWizard({ open, onOpenChange, onComplete })
|
|
| 301 |
value={sequenceSteps}
|
| 302 |
onChange={setSequenceSteps}
|
| 303 |
linkedinDefaults={linkedinDefaults}
|
|
|
|
| 304 |
/>
|
| 305 |
) : step === 3 ? (
|
| 306 |
<PlaceholderStep
|
|
|
|
| 36 |
const [estimatedContacts, setEstimatedContacts] = useState(0);
|
| 37 |
const [sequenceSteps, setSequenceSteps] = useState(() => createDefaultSequenceSteps());
|
| 38 |
const [linkedinDefaults, setLinkedinDefaults] = useState(null);
|
| 39 |
+
const [mailboxDefaults, setMailboxDefaults] = useState(null);
|
| 40 |
|
| 41 |
const reset = useCallback(() => {
|
| 42 |
setStep(1);
|
|
|
|
| 77 |
useEffect(() => {
|
| 78 |
if (!open) {
|
| 79 |
setLinkedinDefaults(null);
|
| 80 |
+
setMailboxDefaults(null);
|
| 81 |
return;
|
| 82 |
}
|
| 83 |
let cancelled = false;
|
| 84 |
+
Promise.allSettled([
|
| 85 |
+
apiFetch('/api/unipile/linkedin/campaign-defaults').then((r) => r.json()),
|
| 86 |
+
apiFetch('/api/unipile/mailbox/campaign-defaults').then((r) => r.json()),
|
| 87 |
+
]).then(([li, mb]) => {
|
| 88 |
+
if (cancelled) return;
|
| 89 |
+
setLinkedinDefaults(
|
| 90 |
+
li.status === 'fulfilled'
|
| 91 |
+
? li.value
|
| 92 |
+
: {
|
| 93 |
+
accounts: [],
|
| 94 |
+
linkedin_profile_display_name: '',
|
| 95 |
+
default_unipile_account_ref_id: null,
|
| 96 |
+
}
|
| 97 |
+
);
|
| 98 |
+
setMailboxDefaults(
|
| 99 |
+
mb.status === 'fulfilled'
|
| 100 |
+
? mb.value
|
| 101 |
+
: {
|
| 102 |
+
accounts: [],
|
| 103 |
+
mailbox_profile_display_name: '',
|
| 104 |
+
default_mailbox_unipile_account_ref_id: null,
|
| 105 |
+
}
|
| 106 |
+
);
|
| 107 |
+
});
|
| 108 |
return () => {
|
| 109 |
cancelled = true;
|
| 110 |
};
|
|
|
|
| 313 |
value={sequenceSteps}
|
| 314 |
onChange={setSequenceSteps}
|
| 315 |
linkedinDefaults={linkedinDefaults}
|
| 316 |
+
mailboxDefaults={mailboxDefaults}
|
| 317 |
/>
|
| 318 |
) : step === 3 ? (
|
| 319 |
<PlaceholderStep
|