mirror of
https://github.com/dograh-hq/dograh.git
synced 2026-06-13 08:15:21 +02:00
feat(lead-gen): delayed Hire-an-Expert nudge on the workflow builder
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ccb6b5d7bc
commit
704787a05e
2 changed files with 91 additions and 0 deletions
|
|
@ -14,6 +14,7 @@ import { createWorkflowDraftApiV1WorkflowWorkflowIdCreateDraftPost, getWorkflowV
|
|||
import type { DocumentResponseSchema, RecordingResponseSchema, ToolResponse } from '@/client/types.gen';
|
||||
import { useNodeSpecs } from "@/components/flow/renderer";
|
||||
import { FlowEdge, FlowNode, NodeType } from "@/components/flow/types";
|
||||
import { HireExpertNudge } from "@/components/lead-forms/HireExpertNudge";
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Sheet, SheetContent } from '@/components/ui/sheet';
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
|
|
@ -481,6 +482,7 @@ function RenderWorkflow({
|
|||
return (
|
||||
<WorkflowProvider value={workflowContextValue}>
|
||||
<div className="flex flex-col h-screen min-w-fit">
|
||||
<HireExpertNudge workflowId={workflowId} />
|
||||
{/* New Workflow Editor Header */}
|
||||
<WorkflowEditorHeader
|
||||
workflowName={workflowName}
|
||||
|
|
|
|||
89
ui/src/components/lead-forms/HireExpertNudge.tsx
Normal file
89
ui/src/components/lead-forms/HireExpertNudge.tsx
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
"use client";
|
||||
|
||||
import { UserRound, X } from "lucide-react";
|
||||
import posthog from "posthog-js";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
|
||||
import { PostHogEvent } from "@/constants/posthog-events";
|
||||
import { useLeadForms } from "@/context/LeadFormsContext";
|
||||
|
||||
interface HireExpertNudgeProps {
|
||||
workflowId: number;
|
||||
}
|
||||
|
||||
// Timings. Override SHOW_DELAY_MS to a few seconds during manual testing.
|
||||
const SHOW_DELAY_MS = 5 * 60 * 1000; // 5 minutes on the builder
|
||||
const AUTO_FADE_MS = 30 * 1000; // visible for 30s
|
||||
|
||||
function nudgeDoneKey(workflowId: number) {
|
||||
return `dograh:hireNudge:${workflowId}`;
|
||||
}
|
||||
|
||||
export function HireExpertNudge({ workflowId }: HireExpertNudgeProps) {
|
||||
const { openHireExpert, hasOpenedHireRef } = useLeadForms();
|
||||
const [visible, setVisible] = useState(false);
|
||||
const fadeTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
|
||||
// Arm the 5-minute show timer (once per mount / workflow).
|
||||
useEffect(() => {
|
||||
if (typeof window === "undefined") return;
|
||||
// Already shown+consumed for this workflow → skip.
|
||||
if (localStorage.getItem(nudgeDoneKey(workflowId))) return;
|
||||
|
||||
const showTimer = setTimeout(() => {
|
||||
if (hasOpenedHireRef.current) return; // they engaged elsewhere; don't nag
|
||||
if (localStorage.getItem(nudgeDoneKey(workflowId))) return;
|
||||
setVisible(true);
|
||||
posthog.capture(PostHogEvent.HIRE_NUDGE_SHOWN, { workflowId });
|
||||
// Auto-fade after 30s. Auto-expiry does NOT mark done (per spec).
|
||||
fadeTimer.current = setTimeout(() => {
|
||||
setVisible(false);
|
||||
posthog.capture(PostHogEvent.HIRE_NUDGE_EXPIRED, { workflowId });
|
||||
}, AUTO_FADE_MS);
|
||||
}, SHOW_DELAY_MS);
|
||||
|
||||
return () => {
|
||||
clearTimeout(showTimer);
|
||||
if (fadeTimer.current) clearTimeout(fadeTimer.current);
|
||||
};
|
||||
}, [workflowId, hasOpenedHireRef]);
|
||||
|
||||
if (!visible) return null;
|
||||
|
||||
const markDone = () => {
|
||||
if (fadeTimer.current) clearTimeout(fadeTimer.current);
|
||||
localStorage.setItem(nudgeDoneKey(workflowId), "1");
|
||||
setVisible(false);
|
||||
};
|
||||
|
||||
const handleClick = () => {
|
||||
posthog.capture(PostHogEvent.HIRE_NUDGE_CLICKED, { workflowId });
|
||||
markDone();
|
||||
openHireExpert("builder_nudge");
|
||||
};
|
||||
|
||||
const handleDismiss = () => {
|
||||
posthog.capture(PostHogEvent.HIRE_NUDGE_DISMISSED, { workflowId });
|
||||
markDone();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="fixed bottom-6 right-6 z-50 flex max-w-xs items-center gap-3 rounded-lg border border-primary bg-background p-3 shadow-lg animate-in fade-in slide-in-from-bottom-2">
|
||||
<button type="button" onClick={handleClick} className="flex flex-1 items-center gap-3 text-left">
|
||||
<UserRound className="h-5 w-5 shrink-0 text-primary" />
|
||||
<span>
|
||||
<span className="block text-sm font-semibold">Hire an Expert</span>
|
||||
<span className="block text-xs text-muted-foreground">We'll build your agent for you</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleDismiss}
|
||||
aria-label="Dismiss"
|
||||
className="shrink-0 text-muted-foreground hover:text-foreground"
|
||||
>
|
||||
<X className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue