diff --git a/apps/web/src/modules/marketing/get-started/step-success.tsx b/apps/web/src/modules/marketing/get-started/step-success.tsx index d819014..9084a1d 100644 --- a/apps/web/src/modules/marketing/get-started/step-success.tsx +++ b/apps/web/src/modules/marketing/get-started/step-success.tsx @@ -1,5 +1,7 @@ "use client"; +import { useCallback, useEffect, useState } from "react"; +import { useSearchParams } from "next/navigation"; import { useTranslation } from "@turbostarter/i18n"; import { cn } from "@turbostarter/ui"; import { buttonVariants } from "@turbostarter/ui-web/button"; @@ -8,51 +10,216 @@ interface StepSuccessProps { email: string; } +interface OrderStatus { + orderId: string; + status: "pending" | "processing" | "completed" | "failed"; + businessName: string; + reputationScore: number | null; + reviewsCount: number | null; + pdfUrl: string | null; + executionId: string | null; + error: string | null; +} + +const STAGES = [ + { key: "scrape", label: "Collecting reviews" }, + { key: "classify", label: "Analyzing sentiment" }, + { key: "synthesize", label: "Generating report" }, + { key: "done", label: "Complete" }, +] as const; + +function getStageIndex(status: string): number { + if (status === "pending") return 0; + if (status === "processing") return 1; + if (status === "completed") return 3; + return -1; +} + export const StepSuccess = ({ email }: StepSuccessProps) => { const { t } = useTranslation("marketing"); + const searchParams = useSearchParams(); + const sessionId = searchParams.get("session_id"); + + const [orderStatus, setOrderStatus] = useState(null); + const [polling, setPolling] = useState(true); + + const pollStatus = useCallback(async () => { + if (!sessionId) return; + + try { + const res = await fetch(`/api/blueprint/status/${sessionId}`); + if (res.ok) { + const data = (await res.json()) as OrderStatus; + setOrderStatus(data); + + if (data.status === "completed" || data.status === "failed") { + setPolling(false); + } + } + } catch { + // Silently retry on next interval + } + }, [sessionId]); + + useEffect(() => { + pollStatus(); + + if (!polling) return; + + const interval = setInterval(pollStatus, 5000); + return () => clearInterval(interval); + }, [pollStatus, polling]); + + const isCompleted = orderStatus?.status === "completed"; + const isFailed = orderStatus?.status === "failed"; + const stageIndex = orderStatus ? getStageIndex(orderStatus.status) : 0; return (
- {/* Success icon */} -
- - - + {/* Header icon */} +
+ {isCompleted ? ( + + + + ) : isFailed ? ( + + + + ) : ( +
+ )}
+ {/* Title */}

- {t("wizard.success.title")} + {isCompleted + ? t("wizard.success.readyTitle") + : isFailed + ? t("wizard.success.failedTitle") + : t("wizard.success.title")}

- {t("wizard.success.description", { - email: email || "your email", - })} + {isCompleted + ? t("wizard.success.readyDescription", { + email: email || "your email", + }) + : isFailed + ? orderStatus?.error || "We encountered an error processing your report." + : t("wizard.success.description", { + email: email || "your email", + })}

- {/* Processing indicator */} -
-
-
- - {t("wizard.success.processing")} + {/* Score highlight (when complete) */} + {isCompleted && orderStatus?.reputationScore && ( +
+ Reputation Score + + {orderStatus.reputationScore} + /100 + {orderStatus.reviewsCount && ( + + Based on {orderStatus.reviewsCount} reviews + + )}
-

- {t("wizard.success.delivery")} -

-
+ )} + + {/* Progress stages (when processing) */} + {!isCompleted && !isFailed && ( +
+
+ {STAGES.map((stage, i) => { + const isActive = i === stageIndex || (i === 1 && stageIndex < 3); + const isDone = i < stageIndex || (isCompleted && i <= 3); + + return ( +
+ {isDone ? ( + + + + ) : isActive ? ( +
+ ) : ( +
+ )} + + {stage.label} + +
+ ); + })} +
+

+ {t("wizard.success.delivery")} +

+
+ )} + + {/* Download / Dashboard CTAs (when complete) */} + {isCompleted && orderStatus?.pdfUrl && ( + + )} {/* Create account section */}
diff --git a/packages/i18n/src/translations/en/marketing.json b/packages/i18n/src/translations/en/marketing.json index 0047908..0e6d711 100644 --- a/packages/i18n/src/translations/en/marketing.json +++ b/packages/i18n/src/translations/en/marketing.json @@ -440,6 +440,9 @@ "success": { "title": "Your Blueprint is on the way!", "description": "We're analyzing your reviews now. Your Reputation Blueprint will be delivered to {{email}} within 24 hours.", + "readyTitle": "Your Report is Ready!", + "readyDescription": "We've sent the report to {{email}}", + "failedTitle": "Something went wrong", "processing": "Analyzing reviews...", "createAccount": "Create an account", "createAccountDescription": "Track your report status and download it when ready.", diff --git a/packages/i18n/src/translations/es/marketing.json b/packages/i18n/src/translations/es/marketing.json index 39d8671..ecad4b6 100644 --- a/packages/i18n/src/translations/es/marketing.json +++ b/packages/i18n/src/translations/es/marketing.json @@ -440,6 +440,9 @@ "success": { "title": "¡Tu Radiografía está en camino!", "description": "Estamos analizando tus reseñas. Tu Radiografía de Reputación se entregará a {{email}} en 24 horas.", + "readyTitle": "¡Tu Informe está Listo!", + "readyDescription": "Hemos enviado el informe a {{email}}", + "failedTitle": "Algo salió mal", "processing": "Analizando reseñas...", "createAccount": "Crear una cuenta", "createAccountDescription": "Sigue el estado de tu informe y descárgalo cuando esté listo.",