Merge pull request #34 from WIT-LAB-LLC/develop

fix funnel
This commit is contained in:
pennyteenycat 2025-10-09 13:19:38 +02:00 committed by GitHub
commit cd8df68fc3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 179 additions and 88 deletions

View File

@ -170,7 +170,7 @@
},
"navigation": {
"rules": [],
"defaultNextScreenId": "relationship-status",
"defaultNextScreenId": "analysis-target",
"isEndScreen": false
},
"list": {
@ -269,6 +269,15 @@
"align": "left",
"color": "default"
},
"subtitle": {
"text": "This helps make the portrait and insights more accurate.",
"show": true,
"font": "manrope",
"weight": "regular",
"size": "md",
"align": "center",
"color": "default"
},
"bottomActionButton": {
"show": false,
"cornerRadius": "3xl",
@ -2195,7 +2204,7 @@
{
"conditions": [
{
"screenId": "gender",
"screenId": "partner-gender",
"operator": "includesAny",
"optionIds": [
"male"
@ -2339,7 +2348,7 @@
},
"icon": "lock"
},
"buttonText": "Get Me Soulmate Sketch"
"buttonText": "Get My Soulmate Sketch"
},
"joinedToday": {
"count": {
@ -2351,7 +2360,7 @@
},
"trustedByOver": {
"text": {
"text": "Trusted by over 355,000 people."
"text": "Trusted by over **355,000 people."
}
},
"findingOneGuide": {
@ -2364,7 +2373,7 @@
}
},
"text": {
"text": "You're not just looking for someone — you're. You're not just looking for someone — you'reYou're not just looking for someone — you'reYou're not just looking for someone — you'reYou're not just looking for someone — you're. You're not just looking for someone — you're. You're not just looking for someone — you'reYou're not just looking for someone — you'reYou're not just looking for someone — you'reYou're not just looking for someone — you're"
"text": "Youre special — you have imagination and energy that not everyone can understand. You deserve more than to be “half-understood” — you deserve to meet someone who sees the world as deeply and vividly as you do. This guide will help you recognize the signs of destiny, trust your path, and find the one whose heart is already connected to yours."
},
"blur": {
"text": {
@ -2473,7 +2482,7 @@
"src": "/trial-payment/users-portraits/6.jpg"
}
],
"buttonText": "Get me soulmate sketch"
"buttonText": "Get My Soulmate Sketch"
},
"joinedTodayWithAvatars": {
"count": {
@ -2642,7 +2651,7 @@
"title": {
"text": "Still have questions? We're here to help!"
},
"actionButtonText": "Get me Soulmate Sketch",
"actionButtonText": "Get My Soulmate Sketch",
"contactButtonText": "Contact Support"
},
"commonQuestions": {
@ -2677,8 +2686,8 @@
"text": "CONTACTS"
},
"email": {
"href": "support@witlab.com",
"text": "support@witlab.com"
"href": "info@witlab.us",
"text": "info@witlab.us"
},
"address": {
"text": "Wit Lab 2108 N ST STE N SACRAMENTO, CA95816, US"
@ -2690,15 +2699,15 @@
},
"links": [
{
"href": "https://witlab.us",
"href": "https://witlab.com/terms",
"text": "Terms of Service"
},
{
"href": "https://witlab.us",
"href": "https://witlab.com/privacy",
"text": "Privacy Policy"
},
{
"href": "https://witlab.us",
"href": "https://witlab.com/refund",
"text": "Refund Policy"
}
],

View File

@ -56,7 +56,13 @@ export default function Contacts({
email.className
)}
>
<Link href={`mailto:${email.href}`}>{email.children}</Link>
<Link
href={email.href.startsWith('http') ? email.href : `mailto:${email.href}`}
target={email.href.startsWith('http') ? "_blank" : undefined}
rel={email.href.startsWith('http') ? "noopener noreferrer" : undefined}
>
{email.children}
</Link>
</Button>
</div>
)}

View File

@ -45,7 +45,7 @@ export default function Legal({
link.className
)}
>
<Link href={link.href}>{link.children}</Link>
<Link href={link.href} target="_blank" rel="noopener noreferrer">{link.children}</Link>
</Button>
))}
</div>

View File

@ -3,14 +3,26 @@ import Typography, {
} from "@/components/ui/Typography/Typography";
import { cn } from "@/lib/utils";
interface PolicyProps extends React.ComponentProps<"div"> {
interface PolicyProps extends Omit<React.ComponentProps<"div">, "children"> {
text?: TypographyProps<"p">;
children?: React.ReactNode; // Support custom content with links
}
export default function Policy({ text, ...props }: PolicyProps) {
export default function Policy({ text, children, ...props }: PolicyProps) {
return (
<div {...props} className={cn("w-full", props.className)}>
{text && (
{children ? (
// Custom content (e.g., with links)
<Typography
as="p"
font="inter"
size="xs"
className="text-[#6B7280]"
>
{children}
</Typography>
) : text ? (
// Legacy text prop support
<Typography
as="p"
font="inter"
@ -18,7 +30,7 @@ export default function Policy({ text, ...props }: PolicyProps) {
{...text}
className={cn("text-[#6B7280]", text.className)}
/>
)}
) : null}
</div>
);
}

View File

@ -1,6 +1,6 @@
"use client";
import { useState } from "react";
import { useState, useRef, useEffect } from "react";
import { Coupon } from "@/components/widgets/Coupon/Coupon";
import Typography from "@/components/ui/Typography/Typography";
@ -9,6 +9,7 @@ import { buildTypographyProps } from "@/lib/funnel/mappers";
import type { CouponScreenDefinition, DefaultTexts } from "@/lib/funnel/types";
import { TemplateLayout } from "../layouts/TemplateLayout";
import { createTemplateLayoutProps } from "@/lib/funnel/templateHelpers";
import { cn } from "@/lib/utils";
interface CouponTemplateProps {
screen: CouponScreenDefinition;
@ -28,15 +29,38 @@ export function CouponTemplate({
defaultTexts,
}: CouponTemplateProps) {
const [copiedCode, setCopiedCode] = useState<string | null>(null);
const [isVisible, setIsVisible] = useState(false);
const [animationKey, setAnimationKey] = useState(0);
const fadeTimeoutRef = useRef<NodeJS.Timeout | null>(null);
const removeTimeoutRef = useRef<NodeJS.Timeout | null>(null);
// Cleanup timeouts on unmount
useEffect(() => {
return () => {
if (fadeTimeoutRef.current) clearTimeout(fadeTimeoutRef.current);
if (removeTimeoutRef.current) clearTimeout(removeTimeoutRef.current);
};
}, []);
const handleCopyPromoCode = (code: string) => {
// Clear existing timeouts
if (fadeTimeoutRef.current) clearTimeout(fadeTimeoutRef.current);
if (removeTimeoutRef.current) clearTimeout(removeTimeoutRef.current);
navigator.clipboard.writeText(code);
setCopiedCode(code);
setIsVisible(true);
setAnimationKey(prev => prev + 1); // Force animation restart
setTimeout(() => {
// Start fade out animation before removing
fadeTimeoutRef.current = setTimeout(() => {
setIsVisible(false);
}, 2500);
// Remove from DOM after animation completes
removeTimeoutRef.current = setTimeout(() => {
setCopiedCode(null);
}, 2000);
}, 3000);
};
const couponProps = {
@ -118,12 +142,23 @@ export function CouponTemplate({
return (
<TemplateLayout {...layoutProps}>
<div className="w-full flex flex-col items-center justify-center mt-[22px]">
<div className="mb-8">
<Coupon {...couponProps} />
</div>
<div className="relative mb-8">
{/* Copied message positioned above coupon in available space */}
{copiedCode && (
<div className="mb-4 p-3 bg-green-50 border border-green-200 rounded-lg">
<div
key={animationKey}
className={cn(
"absolute left-1/2 -translate-x-1/2",
"-top-[56px]", // Position in the space above coupon
"px-4 py-3 bg-green-50 border border-green-200 rounded-lg shadow-lg",
"transition-all duration-500 z-10",
"max-w-[280px]",
"whitespace-nowrap",
isVisible
? "animate-in fade-in slide-in-from-top-2 opacity-100"
: "animate-out fade-out slide-out-to-top-2 opacity-0"
)}
>
<Typography
as="p"
size="sm"
@ -138,6 +173,9 @@ export function CouponTemplate({
</Typography>
</div>
)}
<Coupon {...couponProps} />
</div>
</div>
</TemplateLayout>
);

View File

@ -206,15 +206,15 @@ const defaultScreen: TrialPaymentScreenDefinition = {
title: { text: "WIT LAB ©" },
contacts: {
title: { text: "CONTACTS" },
email: { href: "support@witlab.com", text: "support@witlab.com" },
email: { href: "https://witlab.us", text: "Contact" },
address: { text: "Wit Lab 2108 N ST STE N SACRAMENTO, CA95816, US" },
},
legal: {
title: { text: "LEGAL" },
links: [
{ href: "https://witlab.us", text: "Terms of Service" },
{ href: "https://witlab.us", text: "Privacy Policy" },
{ href: "https://witlab.us", text: "Refund Policy" },
{ href: "https://witlab.us/terms", text: "Terms of Service" },
{ href: "https://witlab.us/privacy", text: "Privacy Policy" },
{ href: "https://witlab.us/refund", text: "Refund Policy" },
],
copyright: {
text:

View File

@ -128,7 +128,7 @@ export function TrialPaymentTemplate({
if (paymentSectionRef.current) {
paymentSectionRef.current.scrollIntoView({
behavior: "smooth",
block: "start",
block: "end", // Policy text at bottom of screen
});
}
};
@ -285,7 +285,7 @@ export function TrialPaymentTemplate({
initialSeconds: screen.headerBlock.timerSeconds ?? 600,
}}
button={{
children: defaultTexts?.continueButton || "Continue",
children: "Get Sketch",
onClick: scrollToPayment,
}}
/>
@ -575,7 +575,7 @@ export function TrialPaymentTemplate({
)}
{screen.paymentButtons && (
<div ref={paymentSectionRef} className="w-full">
<div className="w-full">
<PaymentButtons
className="mt-[46px]"
buttons={screen.paymentButtons.buttons.map((b, index) => {
@ -684,18 +684,29 @@ export function TrialPaymentTemplate({
)}
{screen.policy && (
<Policy
className="mt-4"
text={buildTypographyProps(
screen.policy.text
? {
...screen.policy.text,
text: replacePlaceholders(screen.policy.text.text),
}
: undefined,
{ as: "p", defaults: { font: "inter", size: "xs" } }
)}
/>
<div ref={paymentSectionRef}>
<Policy className="mt-4">
By clicking Continue, you agree to our{" "}
<a
href="https://witlab.us/terms"
target="_blank"
rel="noopener noreferrer"
className="underline hover:text-[#4B5563]"
>
Terms of Use & Service
</a>{" "}
and{" "}
<a
href="https://witlab.us/privacy"
target="_blank"
rel="noopener noreferrer"
className="underline hover:text-[#4B5563]"
>
Privacy Policy
</a>
. You also acknowledge that your 1-week introductory plan to Wit Lab LLC, billed at $1.00, will automatically renew at $14.99 every 1 week unless canceled before the end of the trial period.
</Policy>
</div>
)}
{screen.usersPortraits && (
@ -947,7 +958,13 @@ export function TrialPaymentTemplate({
screen.stillHaveQuestions.contactButtonText
? {
children: screen.stillHaveQuestions.contactButtonText,
onClick: scrollToPayment,
onClick: () => {
// Open contact link from footer config
const contactUrl = screen.footer?.contacts?.email?.href;
if (contactUrl) {
window.open(contactUrl, "_blank", "noopener,noreferrer");
}
},
}
: undefined
}

View File

@ -135,11 +135,11 @@ export function TemplateLayout({
<PrivacyTermsConsent
className="mt-2"
privacyPolicy={{
href: "https://witlab.us",
href: "https://witlab.us/privacy",
children: "Privacy Policy",
}}
termsOfUse={{
href: "https://witlab.us",
href: "https://witlab.us/terms",
children: "Terms of use",
}}
/>

View File

@ -53,11 +53,11 @@ const meta: Meta<typeof Email> = {
privacyTermsConsentProps: {
privacyPolicy: {
children: "Privacy Policy",
href: "https://witlab.us",
href: "https://witlab.us/privacy",
},
termsOfUse: {
children: "Terms of use",
href: "https://witlab.us",
href: "https://witlab.us/terms",
},
},
privacySecurityBannerProps: {

View File

@ -21,11 +21,11 @@ const meta: Meta<typeof SoulmatePortrait> = {
privacyTermsConsentProps: {
privacyPolicy: {
children: "Privacy Policy",
href: "https://witlab.us",
href: "https://witlab.us/privacy",
},
termsOfUse: {
children: "Terms of use",
href: "https://witlab.us",
href: "https://witlab.us/terms",
},
},
title: {

View File

@ -718,8 +718,8 @@ const meta: Meta<typeof TrialPayment> = {
children: "CONTACTS",
},
email: {
href: "support@witlab.com",
children: "support@witlab.com",
href: "https://witlab.us",
children: "Contact",
},
address: {
children: "Wit Lab 2108 N ST STE N SACRAMENTO, CA95816, US",
@ -730,9 +730,9 @@ const meta: Meta<typeof TrialPayment> = {
children: "LEGAL",
},
links: [
{ href: "https://witlab.us", children: "Terms of Service" },
{ href: "https://witlab.us", children: "Privacy Policy" },
{ href: "https://witlab.us", children: "Refund Policy" },
{ href: "https://witlab.us/terms", children: "Terms of Service" },
{ href: "https://witlab.us/privacy", children: "Privacy Policy" },
{ href: "https://witlab.us/refund", children: "Refund Policy" },
],
copyright: {
children:

View File

@ -27,13 +27,13 @@ export default function PrivacyTermsConsent({
I agree to the{" "}
{privacyPolicy && (
<Button variant="link" asChild {...privacyPolicy}>
<Link href={privacyPolicy.href}>{privacyPolicy.children}</Link>
<Link href={privacyPolicy.href} target="_blank" rel="noopener noreferrer">{privacyPolicy.children}</Link>
</Button>
)}
{", "}
{termsOfUse && (
<Button variant="link" asChild {...termsOfUse}>
<Link href={termsOfUse.href}>{termsOfUse.children}</Link>
<Link href={termsOfUse.href} target="_blank" rel="noopener noreferrer">{termsOfUse.children}</Link>
</Button>
)}{" "}
and to the use of cookies and tracking technologies, that require your

View File

@ -175,15 +175,15 @@ export function buildTrialPaymentDefaults(id?: string): TrialPaymentScreenDefini
title: { text: "WIT LAB ©" },
contacts: {
title: { text: "CONTACTS" },
email: { href: "support@witlab.com", text: "support@witlab.com" },
email: { href: "https://witlab.us", text: "Contact" },
address: { text: "Wit Lab 2108 N ST STE N SACRAMENTO, CA95816, US" },
},
legal: {
title: { text: "LEGAL" },
links: [
{ href: "https://witlab.com/terms", text: "Terms of Service" },
{ href: "https://witlab.com/privacy", text: "Privacy Policy" },
{ href: "https://witlab.com/refund", text: "Refund Policy" },
{ href: "https://witlab.us/terms", text: "Terms of Service" },
{ href: "https://witlab.us/privacy", text: "Privacy Policy" },
{ href: "https://witlab.us/refund", text: "Refund Policy" },
],
copyright: {
text:

View File

@ -178,7 +178,7 @@ export const BAKED_FUNNELS: Record<string, FunnelDefinition> = {
},
"navigation": {
"rules": [],
"defaultNextScreenId": "relationship-status",
"defaultNextScreenId": "analysis-target",
"isEndScreen": false
},
"list": {
@ -277,6 +277,15 @@ export const BAKED_FUNNELS: Record<string, FunnelDefinition> = {
"align": "left",
"color": "default"
},
"subtitle": {
"text": "This helps make the portrait and insights more accurate.",
"show": true,
"font": "manrope",
"weight": "regular",
"size": "md",
"align": "center",
"color": "default"
},
"bottomActionButton": {
"show": false,
"cornerRadius": "3xl",
@ -2203,7 +2212,7 @@ export const BAKED_FUNNELS: Record<string, FunnelDefinition> = {
{
"conditions": [
{
"screenId": "gender",
"screenId": "partner-gender",
"operator": "includesAny",
"optionIds": [
"male"
@ -2347,7 +2356,7 @@ export const BAKED_FUNNELS: Record<string, FunnelDefinition> = {
},
"icon": "lock"
},
"buttonText": "Get Me Soulmate Sketch"
"buttonText": "Get My Soulmate Sketch"
},
"joinedToday": {
"count": {
@ -2359,7 +2368,7 @@ export const BAKED_FUNNELS: Record<string, FunnelDefinition> = {
},
"trustedByOver": {
"text": {
"text": "Trusted by over 355,000 people."
"text": "Trusted by over **355,000 people."
}
},
"findingOneGuide": {
@ -2372,7 +2381,7 @@ export const BAKED_FUNNELS: Record<string, FunnelDefinition> = {
}
},
"text": {
"text": "You're not just looking for someone — you're. You're not just looking for someone — you'reYou're not just looking for someone — you'reYou're not just looking for someone — you'reYou're not just looking for someone — you're. You're not just looking for someone — you're. You're not just looking for someone — you'reYou're not just looking for someone — you'reYou're not just looking for someone — you'reYou're not just looking for someone — you're"
"text": "Youre special — you have imagination and energy that not everyone can understand. You deserve more than to be “half-understood” — you deserve to meet someone who sees the world as deeply and vividly as you do. This guide will help you recognize the signs of destiny, trust your path, and find the one whose heart is already connected to yours."
},
"blur": {
"text": {
@ -2481,7 +2490,7 @@ export const BAKED_FUNNELS: Record<string, FunnelDefinition> = {
"src": "/trial-payment/users-portraits/6.jpg"
}
],
"buttonText": "Get me soulmate sketch"
"buttonText": "Get My Soulmate Sketch"
},
"joinedTodayWithAvatars": {
"count": {
@ -2650,7 +2659,7 @@ export const BAKED_FUNNELS: Record<string, FunnelDefinition> = {
"title": {
"text": "Still have questions? We're here to help!"
},
"actionButtonText": "Get me Soulmate Sketch",
"actionButtonText": "Get My Soulmate Sketch",
"contactButtonText": "Contact Support"
},
"commonQuestions": {
@ -2685,8 +2694,8 @@ export const BAKED_FUNNELS: Record<string, FunnelDefinition> = {
"text": "CONTACTS"
},
"email": {
"href": "support@witlab.com",
"text": "support@witlab.com"
"href": "info@witlab.us",
"text": "info@witlab.us"
},
"address": {
"text": "Wit Lab 2108 N ST STE N SACRAMENTO, CA95816, US"
@ -2698,15 +2707,15 @@ export const BAKED_FUNNELS: Record<string, FunnelDefinition> = {
},
"links": [
{
"href": "https://witlab.us",
"href": "https://witlab.com/terms",
"text": "Terms of Service"
},
{
"href": "https://witlab.us",
"href": "https://witlab.com/privacy",
"text": "Privacy Policy"
},
{
"href": "https://witlab.us",
"href": "https://witlab.com/refund",
"text": "Refund Policy"
}
],