From bd2aca7a76d3f069f4074cf2f3e6fe965aa8023c Mon Sep 17 00:00:00 2001 From: Usman Baig Date: Sun, 8 Feb 2026 15:18:33 +0100 Subject: [PATCH] feat: integrate ScriptSetupBlock component for improved site setup instructions and tracking script functionality across pages --- app/sites/[id]/settings/page.tsx | 34 ++--- app/sites/new/layout.tsx | 14 +++ app/sites/new/page.tsx | 174 +++++++++++++------------- app/welcome/layout.tsx | 14 +++ app/welcome/page.tsx | 85 +------------ components/sites/ScriptSetupBlock.tsx | 124 ++++++++++++++++++ lib/welcomeAnalytics.ts | 10 ++ 7 files changed, 266 insertions(+), 189 deletions(-) create mode 100644 app/sites/new/layout.tsx create mode 100644 app/welcome/layout.tsx create mode 100644 components/sites/ScriptSetupBlock.tsx diff --git a/app/sites/[id]/settings/page.tsx b/app/sites/[id]/settings/page.tsx index 8ea491f..32935e2 100644 --- a/app/sites/[id]/settings/page.tsx +++ b/app/sites/[id]/settings/page.tsx @@ -8,9 +8,10 @@ import { toast } from '@ciphera-net/ui' import { getAuthErrorMessage } from '@/lib/utils/authErrors' import { LoadingOverlay } from '@ciphera-net/ui' import VerificationModal from '@/components/sites/VerificationModal' +import ScriptSetupBlock from '@/components/sites/ScriptSetupBlock' import { PasswordInput } from '@ciphera-net/ui' import { Select, Modal, Button } from '@ciphera-net/ui' -import { APP_URL, API_URL } from '@/lib/api/client' +import { APP_URL } from '@/lib/api/client' import { generatePrivacySnippet } from '@/lib/utils/privacySnippet' import { motion, AnimatePresence } from 'framer-motion' import { useAuth } from '@/lib/auth/context' @@ -69,7 +70,6 @@ export default function SiteSettingsPage() { // Bot and noise filtering filter_bots: true }) - const [scriptCopied, setScriptCopied] = useState(false) const [linkCopied, setLinkCopied] = useState(false) const [snippetCopied, setSnippetCopied] = useState(false) const [showVerificationModal, setShowVerificationModal] = useState(false) @@ -266,14 +266,6 @@ export default function SiteSettingsPage() { } } - const copyScript = () => { - const script = `` - navigator.clipboard.writeText(script) - setScriptCopied(true) - toast.success('Script copied to clipboard') - setTimeout(() => setScriptCopied(false), 2000) - } - const copyLink = () => { const link = `${APP_URL}/share/${siteId}` navigator.clipboard.writeText(link) @@ -443,23 +435,15 @@ export default function SiteSettingsPage() {

Tracking Script

- Add this script to your website to start tracking visitors. + Add this script to your website to start tracking visitors. Choose your framework for setup instructions.

-
- - {``} - - -
+ -
+
- ))} -
-

- - View all integrations → - -

+ +
-
- - {``} - - -
- {selectedIntegrationSlug && getIntegration(selectedIntegrationSlug) && ( -

- - See full {getIntegration(selectedIntegrationSlug)!.name} guide → - -

- )} +
+ +

+ Check if your site is sending data correctly. +

+
+ +
+
-
+ + setShowVerificationModal(false)} + site={createdSite} + /> ) } @@ -175,6 +175,12 @@ export default function NewSitePage() { Create New Site + {atLimit && limitsChecked && ( +

+ Plan limit reached. Upgrade to add more sites. +

+ )} +
)} diff --git a/components/sites/ScriptSetupBlock.tsx b/components/sites/ScriptSetupBlock.tsx new file mode 100644 index 0000000..4d16d76 --- /dev/null +++ b/components/sites/ScriptSetupBlock.tsx @@ -0,0 +1,124 @@ +'use client' + +/** + * Shared block: framework picker, tracking script snippet with copy, and integration guide links. + * Used on welcome (step 5), /sites/new (step 2), and site settings. + */ + +import { useState, useCallback } from 'react' +import Link from 'next/link' +import { API_URL, APP_URL } from '@/lib/api/client' +import { integrations, getIntegration } from '@/lib/integrations' +import { toast } from '@ciphera-net/ui' +import { CheckIcon } from '@ciphera-net/ui' + +const POPULAR_INTEGRATIONS = integrations.filter((i) => i.category === 'framework').slice(0, 10) + +export interface ScriptSetupBlockSite { + domain: string + name?: string +} + +interface ScriptSetupBlockProps { + /** Site domain (and optional name for display). */ + site: ScriptSetupBlockSite + /** Called when user copies the script (e.g. for analytics). */ + onScriptCopy?: () => void + /** Show framework picker and "View all integrations" / "See full guide" links. Default true. */ + showFrameworkPicker?: boolean + /** Optional class for the root wrapper. */ + className?: string +} + +export default function ScriptSetupBlock({ + site, + onScriptCopy, + showFrameworkPicker = true, + className = '', +}: ScriptSetupBlockProps) { + const [selectedIntegrationSlug, setSelectedIntegrationSlug] = useState(null) + const [scriptCopied, setScriptCopied] = useState(false) + + const copyScript = useCallback(() => { + const script = `` + navigator.clipboard.writeText(script) + setScriptCopied(true) + toast.success('Script copied to clipboard') + onScriptCopy?.() + setTimeout(() => setScriptCopied(false), 2000) + }, [site.domain, onScriptCopy]) + + return ( +
+ {showFrameworkPicker && ( + <> +

+ Add the script to your site +

+

+ Choose your framework for setup instructions. +

+
+ {POPULAR_INTEGRATIONS.map((int) => ( + + ))} +
+

+ + View all integrations → + +

+ + )} + +
+ + {``} + + +
+ + {showFrameworkPicker && selectedIntegrationSlug && getIntegration(selectedIntegrationSlug) && ( +

+ + See full {getIntegration(selectedIntegrationSlug)!.name} guide → + +

+ )} +
+ ) +} diff --git a/lib/welcomeAnalytics.ts b/lib/welcomeAnalytics.ts index 9f1ee71..5c2f2db 100644 --- a/lib/welcomeAnalytics.ts +++ b/lib/welcomeAnalytics.ts @@ -13,6 +13,8 @@ export type WelcomeEventName = | 'welcome_site_added' | 'welcome_site_skipped' | 'welcome_completed' + | 'site_created_from_dashboard' + | 'site_created_script_copied' export interface WelcomeEventPayload { event: WelcomeEventName @@ -75,3 +77,11 @@ export function trackWelcomeSiteSkipped() { export function trackWelcomeCompleted(addedSite: boolean) { emit('welcome_completed', { added_site: addedSite }) } + +export function trackSiteCreatedFromDashboard() { + emit('site_created_from_dashboard') +} + +export function trackSiteCreatedScriptCopied() { + emit('site_created_script_copied') +}