From adfe8830d41f24bb57e5f38c662ccde34bea1fe7 Mon Sep 17 00:00:00 2001 From: "dev.daminik00" Date: Wed, 22 Oct 2025 22:42:01 +0200 Subject: [PATCH] add trial choice template --- .../AB_TESTING_GUIDE.md | 0 .../AB_TESTING_IMPLEMENTATION.md | 0 .../AB_TESTING_UPDATES.md | 0 .../MONGODB_SCHEMA_UPDATE.md | 0 .../NAVIGATION_RULES_GUIDE.md | 0 .../UNLEASH_ANALYTICS_FIX.md | 0 .../UNLEASH_ANALYTICS_FLOW.md | 0 .../UNLEASH_LAZY_IMPRESSION_IMPLEMENTATION.md | 0 UNLEASH_SETUP.md => docs/UNLEASH_SETUP.md | 0 .../admin/builder/Canvas/BuilderCanvas.tsx | 38 +++++++++++++ .../builder/Canvas/InsertScreenButton.tsx | 47 ++++++++++++++++ .../admin/builder/Canvas/TransitionRow.tsx | 22 ++++++-- src/components/admin/builder/Canvas/index.ts | 1 + .../builder/templates/TemplateConfig.tsx | 35 +++++++----- src/lib/admin/builder/state/reducer.ts | 55 +++++++++++++++++++ src/lib/admin/builder/state/types.ts | 1 + src/lib/models/Funnel.ts | 1 + 17 files changed, 181 insertions(+), 19 deletions(-) rename AB_TESTING_GUIDE.md => docs/AB_TESTING_GUIDE.md (100%) rename AB_TESTING_IMPLEMENTATION.md => docs/AB_TESTING_IMPLEMENTATION.md (100%) rename AB_TESTING_UPDATES.md => docs/AB_TESTING_UPDATES.md (100%) rename MONGODB_SCHEMA_UPDATE.md => docs/MONGODB_SCHEMA_UPDATE.md (100%) rename NAVIGATION_RULES_GUIDE.md => docs/NAVIGATION_RULES_GUIDE.md (100%) rename UNLEASH_ANALYTICS_FIX.md => docs/UNLEASH_ANALYTICS_FIX.md (100%) rename UNLEASH_ANALYTICS_FLOW.md => docs/UNLEASH_ANALYTICS_FLOW.md (100%) rename UNLEASH_LAZY_IMPRESSION_IMPLEMENTATION.md => docs/UNLEASH_LAZY_IMPRESSION_IMPLEMENTATION.md (100%) rename UNLEASH_SETUP.md => docs/UNLEASH_SETUP.md (100%) create mode 100644 src/components/admin/builder/Canvas/InsertScreenButton.tsx diff --git a/AB_TESTING_GUIDE.md b/docs/AB_TESTING_GUIDE.md similarity index 100% rename from AB_TESTING_GUIDE.md rename to docs/AB_TESTING_GUIDE.md diff --git a/AB_TESTING_IMPLEMENTATION.md b/docs/AB_TESTING_IMPLEMENTATION.md similarity index 100% rename from AB_TESTING_IMPLEMENTATION.md rename to docs/AB_TESTING_IMPLEMENTATION.md diff --git a/AB_TESTING_UPDATES.md b/docs/AB_TESTING_UPDATES.md similarity index 100% rename from AB_TESTING_UPDATES.md rename to docs/AB_TESTING_UPDATES.md diff --git a/MONGODB_SCHEMA_UPDATE.md b/docs/MONGODB_SCHEMA_UPDATE.md similarity index 100% rename from MONGODB_SCHEMA_UPDATE.md rename to docs/MONGODB_SCHEMA_UPDATE.md diff --git a/NAVIGATION_RULES_GUIDE.md b/docs/NAVIGATION_RULES_GUIDE.md similarity index 100% rename from NAVIGATION_RULES_GUIDE.md rename to docs/NAVIGATION_RULES_GUIDE.md diff --git a/UNLEASH_ANALYTICS_FIX.md b/docs/UNLEASH_ANALYTICS_FIX.md similarity index 100% rename from UNLEASH_ANALYTICS_FIX.md rename to docs/UNLEASH_ANALYTICS_FIX.md diff --git a/UNLEASH_ANALYTICS_FLOW.md b/docs/UNLEASH_ANALYTICS_FLOW.md similarity index 100% rename from UNLEASH_ANALYTICS_FLOW.md rename to docs/UNLEASH_ANALYTICS_FLOW.md diff --git a/UNLEASH_LAZY_IMPRESSION_IMPLEMENTATION.md b/docs/UNLEASH_LAZY_IMPRESSION_IMPLEMENTATION.md similarity index 100% rename from UNLEASH_LAZY_IMPRESSION_IMPLEMENTATION.md rename to docs/UNLEASH_LAZY_IMPRESSION_IMPLEMENTATION.md diff --git a/UNLEASH_SETUP.md b/docs/UNLEASH_SETUP.md similarity index 100% rename from UNLEASH_SETUP.md rename to docs/UNLEASH_SETUP.md diff --git a/src/components/admin/builder/Canvas/BuilderCanvas.tsx b/src/components/admin/builder/Canvas/BuilderCanvas.tsx index 4a43670..40c59b6 100644 --- a/src/components/admin/builder/Canvas/BuilderCanvas.tsx +++ b/src/components/admin/builder/Canvas/BuilderCanvas.tsx @@ -11,6 +11,7 @@ import type { } from "@/lib/funnel/types"; import { cn } from "@/lib/utils"; import { DropIndicator } from "./DropIndicator"; +import { InsertScreenButton } from "./InsertScreenButton"; import { TransitionRow } from "./TransitionRow"; import { TemplateSummary } from "./TemplateSummary"; import { VariantSummary } from "./VariantSummary"; @@ -24,6 +25,8 @@ export function BuilderCanvas() { const dragStateRef = useRef<{ screenId: string; dragStartIndex: number } | null>(null); const [dropIndex, setDropIndex] = useState(null); const [addScreenDialogOpen, setAddScreenDialogOpen] = useState(false); + const [insertScreenDialogOpen, setInsertScreenDialogOpen] = useState(false); + const [insertAtIndex, setInsertAtIndex] = useState(null); const handleDragStart = useCallback((event: React.DragEvent, screenId: string, index: number) => { event.dataTransfer.effectAllowed = "move"; @@ -115,6 +118,17 @@ export function BuilderCanvas() { dispatch({ type: "add-screen", payload: { template } }); }, [dispatch]); + const handleInsertScreen = useCallback((atIndex: number) => { + setInsertAtIndex(atIndex); + setInsertScreenDialogOpen(true); + }, []); + + const handleInsertScreenWithTemplate = useCallback((template: ScreenDefinition["template"]) => { + if (insertAtIndex !== null) { + dispatch({ type: "insert-screen", payload: { template, atIndex: insertAtIndex } }); + } + }, [dispatch, insertAtIndex]); + const screenTitleMap = useMemo(() => { return screens.reduce>((accumulator, screen) => { accumulator[screen.id] = screen.title?.text || screen.id; @@ -159,10 +173,15 @@ export function BuilderCanvas() { const defaultTargetIndex = defaultNext ? screens.findIndex((candidate) => candidate.id === defaultNext) : null; + const onBackScreenId = screen.navigation?.onBackScreenId; + const backTargetIndex = onBackScreenId + ? screens.findIndex((candidate) => candidate.id === onBackScreenId) + : null; return (
{isDropBefore && } +
+ {onBackScreenId && ( + + )} +
+ + {/* Insert button after each screen */} + handleInsertScreen(index + 1)} /> + {isDropAfter && }
); @@ -301,6 +333,12 @@ export function BuilderCanvas() { onOpenChange={setAddScreenDialogOpen} onAddScreen={handleAddScreenWithTemplate} /> + + ); } diff --git a/src/components/admin/builder/Canvas/InsertScreenButton.tsx b/src/components/admin/builder/Canvas/InsertScreenButton.tsx new file mode 100644 index 0000000..0c29b0f --- /dev/null +++ b/src/components/admin/builder/Canvas/InsertScreenButton.tsx @@ -0,0 +1,47 @@ +"use client"; + +import { Plus } from "lucide-react"; +import { cn } from "@/lib/utils"; +import { useState } from "react"; + +interface InsertScreenButtonProps { + onInsert: () => void; +} + +export function InsertScreenButton({ onInsert }: InsertScreenButtonProps) { + const [isHovered, setIsHovered] = useState(false); + + return ( +
setIsHovered(true)} + onMouseLeave={() => setIsHovered(false)} + > + {/* Hover area - wider for easier interaction */} +
+ + {/* Divider line */} +
+ + {/* Insert button */} + +
+ ); +} diff --git a/src/components/admin/builder/Canvas/TransitionRow.tsx b/src/components/admin/builder/Canvas/TransitionRow.tsx index 98c43fb..13a7d14 100644 --- a/src/components/admin/builder/Canvas/TransitionRow.tsx +++ b/src/components/admin/builder/Canvas/TransitionRow.tsx @@ -1,8 +1,8 @@ -import { ArrowDown, ArrowRight, CircleSlash2, GitBranch } from "lucide-react"; +import { ArrowDown, ArrowRight, ArrowLeft, CircleSlash2, GitBranch } from "lucide-react"; import { cn } from "@/lib/utils"; export interface TransitionRowProps { - type: "default" | "branch" | "end"; + type: "default" | "branch" | "end" | "back"; label: string; targetLabel?: string; targetIndex?: number | null; @@ -18,7 +18,7 @@ export function TransitionRow({ optionSummaries = [], operator, }: TransitionRowProps) { - const Icon = type === "branch" ? GitBranch : type === "end" ? CircleSlash2 : ArrowDown; + const Icon = type === "branch" ? GitBranch : type === "end" ? CircleSlash2 : type === "back" ? ArrowLeft : ArrowDown; return (
@@ -42,7 +48,11 @@ export function TransitionRow({ {label} diff --git a/src/components/admin/builder/Canvas/index.ts b/src/components/admin/builder/Canvas/index.ts index 8f409a3..fb39e74 100644 --- a/src/components/admin/builder/Canvas/index.ts +++ b/src/components/admin/builder/Canvas/index.ts @@ -3,6 +3,7 @@ export { BuilderCanvas } from "./BuilderCanvas"; // Sub-components export { DropIndicator } from "./DropIndicator"; +export { InsertScreenButton } from "./InsertScreenButton"; export { TransitionRow } from "./TransitionRow"; export { TemplateSummary } from "./TemplateSummary"; export { VariantSummary } from "./VariantSummary"; diff --git a/src/components/admin/builder/templates/TemplateConfig.tsx b/src/components/admin/builder/templates/TemplateConfig.tsx index ce762ad..4ccd54f 100644 --- a/src/components/admin/builder/templates/TemplateConfig.tsx +++ b/src/components/admin/builder/templates/TemplateConfig.tsx @@ -294,18 +294,16 @@ interface HeaderControlsProps { } function HeaderControls({ header, onChange }: HeaderControlsProps) { - const activeHeader = header ?? { show: true, showBackButton: true }; - - const handleToggle = (field: "show" | "showBackButton", checked: boolean) => { - if (field === "show" && !checked) { - onChange({ - ...activeHeader, - show: false, - showBackButton: false, - }); - return; - } + const activeHeader = header ?? { + show: true, + showBackButton: true, + showProgress: true + }; + const handleToggle = ( + field: "show" | "showBackButton" | "showProgress", + checked: boolean + ) => { onChange({ ...activeHeader, [field]: checked, @@ -320,11 +318,22 @@ function HeaderControls({ header, onChange }: HeaderControlsProps) { checked={activeHeader.show !== false} onChange={(event) => handleToggle("show", event.target.checked)} /> - Показывать шапку с прогрессом + Показывать шапку экрана {activeHeader.show !== false && ( -
+
+ +