Seth commited on
Commit
8f69e9d
·
1 Parent(s): 7394679
frontend/src/components/campaigns/CampaignsDashboardTab.jsx CHANGED
@@ -183,7 +183,7 @@ export default function CampaignsDashboardTab() {
183
  useEffect(() => {
184
  const tick = async () => {
185
  const list = campaignsRef.current.filter(
186
- (c) => c.fileId && !c.generationComplete
187
  );
188
  if (!list.length) return;
189
  const updates = await Promise.all(
@@ -192,6 +192,13 @@ export default function CampaignsDashboardTab() {
192
  const res = await apiFetch(
193
  `/api/generation-status?file_id=${encodeURIComponent(c.fileId)}`
194
  );
 
 
 
 
 
 
 
195
  if (!res.ok) return { id: c.id, skip: true };
196
  const status = await res.json();
197
  return {
@@ -208,7 +215,11 @@ export default function CampaignsDashboardTab() {
208
  setCampaigns((prev) =>
209
  prev.map((c) => {
210
  const u = updates.find((x) => x.id === c.id);
211
- if (!u || u.skip) return c;
 
 
 
 
212
  return {
213
  ...c,
214
  generationComplete: u.generationComplete,
 
183
  useEffect(() => {
184
  const tick = async () => {
185
  const list = campaignsRef.current.filter(
186
+ (c) => c.fileId && !c.generationComplete && !c.generationStatusUnavailable
187
  );
188
  if (!list.length) return;
189
  const updates = await Promise.all(
 
192
  const res = await apiFetch(
193
  `/api/generation-status?file_id=${encodeURIComponent(c.fileId)}`
194
  );
195
+ if (res.status === 404) {
196
+ return {
197
+ id: c.id,
198
+ skip: false,
199
+ generationStatusUnavailable: true,
200
+ };
201
+ }
202
  if (!res.ok) return { id: c.id, skip: true };
203
  const status = await res.json();
204
  return {
 
215
  setCampaigns((prev) =>
216
  prev.map((c) => {
217
  const u = updates.find((x) => x.id === c.id);
218
+ if (!u) return c;
219
+ if (u.skip) return c;
220
+ if (u.generationStatusUnavailable) {
221
+ return { ...c, generationStatusUnavailable: true };
222
+ }
223
  return {
224
  ...c,
225
  generationComplete: u.generationComplete,
frontend/src/components/campaigns/CreateCampaignWizard.jsx CHANGED
@@ -325,6 +325,8 @@ export default function CreateCampaignWizard({
325
  const promptEditorRef = useRef(null);
326
  const prevGenRunIdRef = useRef(null);
327
  const hydratedCampaignIdRef = useRef(null);
 
 
328
 
329
  const sequenceHasLinkedin = useMemo(
330
  () =>
@@ -361,13 +363,33 @@ export default function CreateCampaignWizard({
361
  }, []);
362
 
363
  useEffect(() => {
364
- if (!open) reset();
365
- }, [open, reset]);
 
 
 
 
 
 
 
 
 
 
366
 
367
  useEffect(() => {
368
  if (!open || !initialCampaign?.id) return;
369
  if (hydratedCampaignIdRef.current === initialCampaign.id) return;
370
  hydratedCampaignIdRef.current = initialCampaign.id;
 
 
 
 
 
 
 
 
 
 
371
  setGenSequences([]);
372
  setGenContacts([]);
373
  setGenRunId(0);
@@ -412,7 +434,7 @@ export default function CreateCampaignWizard({
412
  ? { ...initialCampaign.wizardLinkedinPrompts }
413
  : {}
414
  );
415
- }, [open, initialCampaign?.id]);
416
 
417
  useEffect(() => {
418
  if (!open || !wizardUpload?.fileId || !initialCampaign?.id) return;
@@ -605,12 +627,18 @@ export default function CreateCampaignWizard({
605
  setGenComplete(true);
606
  es.close();
607
  if (eventSourceRef.current === es) eventSourceRef.current = null;
 
 
 
608
  } else if (data.type === 'error') {
609
  console.error(data.error);
610
  alert(`Generation error: ${data.error}`);
611
  setGenRunning(false);
612
  es.close();
613
  if (eventSourceRef.current === es) eventSourceRef.current = null;
 
 
 
614
  }
615
  } catch (e) {
616
  console.error(e);
@@ -762,7 +790,6 @@ export default function CreateCampaignWizard({
762
  generationProgressPercent: Math.min(100, Math.round(genProgress || 0)),
763
  });
764
  onOpenChange(false);
765
- reset();
766
  };
767
 
768
  useEffect(() => {
 
325
  const promptEditorRef = useRef(null);
326
  const prevGenRunIdRef = useRef(null);
327
  const hydratedCampaignIdRef = useRef(null);
328
+ const openRef = useRef(open);
329
+ openRef.current = open;
330
 
331
  const sequenceHasLinkedin = useMemo(
332
  () =>
 
363
  }, []);
364
 
365
  useEffect(() => {
366
+ if (!open) {
367
+ if (genRunning) return;
368
+ reset();
369
+ }
370
+ }, [open, genRunning, reset]);
371
+
372
+ /** Fresh "Create" session — clear any in-component state (including orphan streams). */
373
+ useEffect(() => {
374
+ if (open && !initialCampaign?.id) {
375
+ reset();
376
+ }
377
+ }, [open, initialCampaign?.id, reset]);
378
 
379
  useEffect(() => {
380
  if (!open || !initialCampaign?.id) return;
381
  if (hydratedCampaignIdRef.current === initialCampaign.id) return;
382
  hydratedCampaignIdRef.current = initialCampaign.id;
383
+ const incomingFile = initialCampaign.fileId || null;
384
+ const currentFile = wizardUpload?.fileId ?? null;
385
+ if (eventSourceRef.current) {
386
+ const keepStream =
387
+ !!incomingFile && !!currentFile && incomingFile === currentFile;
388
+ if (!keepStream) {
389
+ eventSourceRef.current.close();
390
+ eventSourceRef.current = null;
391
+ }
392
+ }
393
  setGenSequences([]);
394
  setGenContacts([]);
395
  setGenRunId(0);
 
434
  ? { ...initialCampaign.wizardLinkedinPrompts }
435
  : {}
436
  );
437
+ }, [open, initialCampaign?.id, wizardUpload?.fileId]);
438
 
439
  useEffect(() => {
440
  if (!open || !wizardUpload?.fileId || !initialCampaign?.id) return;
 
627
  setGenComplete(true);
628
  es.close();
629
  if (eventSourceRef.current === es) eventSourceRef.current = null;
630
+ if (!openRef.current) {
631
+ reset();
632
+ }
633
  } else if (data.type === 'error') {
634
  console.error(data.error);
635
  alert(`Generation error: ${data.error}`);
636
  setGenRunning(false);
637
  es.close();
638
  if (eventSourceRef.current === es) eventSourceRef.current = null;
639
+ if (!openRef.current) {
640
+ reset();
641
+ }
642
  }
643
  } catch (e) {
644
  console.error(e);
 
790
  generationProgressPercent: Math.min(100, Math.round(genProgress || 0)),
791
  });
792
  onOpenChange(false);
 
793
  };
794
 
795
  useEffect(() => {