diff --git a/apps/app/src/actions/stripe/fetch-price-details.ts b/apps/app/src/actions/stripe/fetch-price-details.ts index b2d332771c..da6b95eeea 100644 --- a/apps/app/src/actions/stripe/fetch-price-details.ts +++ b/apps/app/src/actions/stripe/fetch-price-details.ts @@ -22,7 +22,12 @@ export type CachedPrices = { const CACHE_DURATION = 30 * 60; // 30 minutes in seconds export async function fetchStripePriceDetails(): Promise { - const cacheKey = 'stripe:managed-prices'; + // Fetch from Stripe + const monthlyPriceId = env.NEXT_PUBLIC_STRIPE_SUBSCRIPTION_MANAGED_MONTHLY_PRICE_ID; + const yearlyPriceId = env.NEXT_PUBLIC_STRIPE_SUBSCRIPTION_MANAGED_YEARLY_PRICE_ID; + + // Create a unique cache key that includes the price IDs + const cacheKey = `stripe:managed-prices:${monthlyPriceId || 'none'}:${yearlyPriceId || 'none'}`; try { // Check cache first @@ -34,10 +39,6 @@ export async function fetchStripePriceDetails(): Promise { console.error('[STRIPE] Error reading from cache:', error); } - // Fetch from Stripe - const monthlyPriceId = env.NEXT_PUBLIC_STRIPE_SUBSCRIPTION_MANAGED_MONTHLY_PRICE_ID; - const yearlyPriceId = env.NEXT_PUBLIC_STRIPE_SUBSCRIPTION_MANAGED_YEARLY_PRICE_ID; - let monthlyPrice: PriceDetails | null = null; let yearlyPrice: PriceDetails | null = null; diff --git a/apps/app/src/app/(app)/setup/components/AnimatedGradientBackground.tsx b/apps/app/src/app/(app)/setup/components/AnimatedGradientBackground.tsx index 11c0a8bfb8..4ba6136d62 100644 --- a/apps/app/src/app/(app)/setup/components/AnimatedGradientBackground.tsx +++ b/apps/app/src/app/(app)/setup/components/AnimatedGradientBackground.tsx @@ -1,163 +1,185 @@ 'use client'; import { Canvas, useFrame } from '@react-three/fiber'; -import { Bloom, EffectComposer } from '@react-three/postprocessing'; import { useEffect, useMemo, useRef } from 'react'; import * as THREE from 'three'; const vertexShader = ` uniform float u_time; -uniform float u_frequency; +uniform float u_scale; uniform vec2 u_mouse; +varying vec3 vNormal; +varying vec3 vPosition; +varying float vNoise; -varying vec2 vUv; -varying float vDisplacement; - -// Classic Perlin 3D Noise +// Simplex 3D Noise vec4 permute(vec4 x){return mod(((x*34.0)+1.0)*x, 289.0);} vec4 taylorInvSqrt(vec4 r){return 1.79284291400159 - 0.85373472095314 * r;} -vec3 fade(vec3 t) {return t*t*t*(t*(t*6.0-15.0)+10.0);} - -float cnoise(vec3 P){ - vec3 Pi0 = floor(P); - vec3 Pi1 = Pi0 + vec3(1.0); - Pi0 = mod(Pi0, 289.0); - Pi1 = mod(Pi1, 289.0); - vec3 Pf0 = fract(P); - vec3 Pf1 = Pf0 - vec3(1.0); - vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x); - vec4 iy = vec4(Pi0.yy, Pi1.yy); - vec4 iz0 = Pi0.zzzz; - vec4 iz1 = Pi1.zzzz; - - vec4 ixy = permute(permute(ix) + iy); - vec4 ixy0 = permute(ixy + iz0); - vec4 ixy1 = permute(ixy + iz1); - - vec4 gx0 = ixy0 / 7.0; - vec4 gy0 = fract(floor(gx0) / 7.0) - 0.5; - gx0 = fract(gx0); - vec4 gz0 = vec4(0.5) - abs(gx0) - abs(gy0); - vec4 sz0 = step(gz0, vec4(0.0)); - gx0 -= sz0 * (step(0.0, gx0) - 0.5); - gy0 -= sz0 * (step(0.0, gy0) - 0.5); - - vec4 gx1 = ixy1 / 7.0; - vec4 gy1 = fract(floor(gx1) / 7.0) - 0.5; - gx1 = fract(gx1); - vec4 gz1 = vec4(0.5) - abs(gx1) - abs(gy1); - vec4 sz1 = step(gz1, vec4(0.0)); - gx1 -= sz1 * (step(0.0, gx1) - 0.5); - gy1 -= sz1 * (step(0.0, gy1) - 0.5); - - vec3 g000 = vec3(gx0.x,gy0.x,gz0.x); - vec3 g100 = vec3(gx0.y,gy0.y,gz0.y); - vec3 g010 = vec3(gx0.z,gy0.z,gz0.z); - vec3 g110 = vec3(gx0.w,gy0.w,gz0.w); - vec3 g001 = vec3(gx1.x,gy1.x,gz1.x); - vec3 g101 = vec3(gx1.y,gy1.y,gz1.y); - vec3 g011 = vec3(gx1.z,gy1.z,gz1.z); - vec3 g111 = vec3(gx1.w,gy1.w,gz1.w); - - vec4 norm0 = taylorInvSqrt(vec4(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110))); - g000 *= norm0.x; - g010 *= norm0.y; - g100 *= norm0.z; - g110 *= norm0.w; - vec4 norm1 = taylorInvSqrt(vec4(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111))); - g001 *= norm1.x; - g011 *= norm1.y; - g101 *= norm1.z; - g111 *= norm1.w; - float n000 = dot(g000, Pf0); - float n100 = dot(g100, vec3(Pf1.x, Pf0.yz)); - float n010 = dot(g010, vec3(Pf0.x, Pf1.y, Pf0.z)); - float n110 = dot(g110, vec3(Pf1.xy, Pf0.z)); - float n001 = dot(g001, vec3(Pf0.xy, Pf1.z)); - float n101 = dot(g101, vec3(Pf1.x, Pf0.y, Pf1.z)); - float n011 = dot(g011, vec3(Pf0.x, Pf1.yz)); - float n111 = dot(g111, Pf1); - - vec3 fade_xyz = fade(Pf0); - vec4 n_z = mix(vec4(n000, n100, n010, n110), vec4(n001, n101, n011, n111), fade_xyz.z); - vec2 n_yz = mix(n_z.xy, n_z.zw, fade_xyz.y); - float n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x); - return 2.2 * n_xyz; +float snoise(vec3 v){ + const vec2 C = vec2(1.0/6.0, 1.0/3.0) ; + const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); + vec3 i = floor(v + dot(v, C.yyy) ); + vec3 x0 = v - i + dot(i, C.xxx) ; + vec3 g = step(x0.yzx, x0.xyz); + vec3 l = 1.0 - g; + vec3 i1 = min( g.xyz, l.zxy ); + vec3 i2 = max( g.xyz, l.zxy ); + vec3 x1 = x0 - i1 + 1.0 * C.xxx; + vec3 x2 = x0 - i2 + 2.0 * C.xxx; + vec3 x3 = x0 - 1. + 3.0 * C.xxx; + i = mod(i, 289.0 ); + vec4 p = permute( permute( permute( + i.z + vec4(0.0, i1.z, i2.z, 1.0 )) + + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) + + i.x + vec4(0.0, i1.x, i2.x, 1.0 )); + float n_ = 1.0/7.0; + vec3 ns = n_ * D.wyz - D.xzx; + vec4 j = p - 49.0 * floor(p * ns.z *ns.z); + vec4 x_ = floor(j * ns.z); + vec4 y_ = floor(j - 7.0 * x_ ); + vec4 x = x_ *ns.x + ns.yyyy; + vec4 y = y_ *ns.x + ns.yyyy; + vec4 h = 1.0 - abs(x) - abs(y); + vec4 b0 = vec4( x.xy, y.xy ); + vec4 b1 = vec4( x.zw, y.zw ); + vec4 s0 = floor(b0)*2.0 + 1.0; + vec4 s1 = floor(b1)*2.0 + 1.0; + vec4 sh = -step(h, vec4(0.0)); + vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ; + vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ; + vec3 p0 = vec3(a0.xy,h.x); + vec3 p1 = vec3(a0.zw,h.y); + vec3 p2 = vec3(a1.xy,h.z); + vec3 p3 = vec3(a1.zw,h.w); + vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3))); + p0 *= norm.x; + p1 *= norm.y; + p2 *= norm.z; + p3 *= norm.w; + vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0); + m = m * m; + return 42.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1), dot(p2,x2), dot(p3,x3) ) ); } void main() { - vUv = uv; + vNormal = normalize(normalMatrix * normal); + vPosition = position; + + vec3 pos = position; + + // Mouse influence calculations + vec2 mouseOffset = u_mouse - 0.5; + float mouseDistance = length(mouseOffset); + vec3 mouseDir3D = normalize(vec3(mouseOffset.x, mouseOffset.y, 0.0)); + + // Stretch the orb 10% towards mouse position + float stretchAmount = 0.1; // 10% stretch + float dotProduct = dot(normalize(pos), mouseDir3D); + float stretchFactor = 1.0 + stretchAmount * max(0.0, dotProduct); + pos *= stretchFactor; - // Create animated displacement with stronger morphing and wave patterns - float displacement = cnoise(position + vec3(u_time * 0.2)) * 0.3; // Reduced from 0.4 for more wave visibility - displacement += cnoise(position * 2.0 + vec3(u_time * 0.3)) * 0.15; // Reduced from 0.2 + // Dynamic geometric distortions + float angle = atan(pos.y, pos.x); + float radius = length(pos.xy); - // Primary wave patterns - these create the main flowing effect - displacement += sin(position.x * 10.0 + u_time * 2.0) * 0.1; // Increased from 0.08 - displacement += sin(position.y * 10.0 + u_time * 2.5) * 0.1; // Increased speed variation - displacement += sin(position.z * 10.0 + u_time * 3.0) * 0.1; // More speed variation + // Hexagonal-like patterns influenced by mouse + float hex = sin(angle * 6.0 + u_time - mouseDistance * 3.0) * 0.08; + hex += cos(angle * 12.0 - u_time * 1.5 + mouseOffset.x * 5.0) * 0.04; - // Secondary wave patterns for complex organic flow - displacement += sin(position.x * 5.0 - u_time * 1.5) * 0.08; // Increased from 0.06 - displacement += sin(position.y * 5.0 - u_time * 2.0) * 0.08; - displacement += cos(position.z * 7.0 + u_time * 1.0) * 0.06; // Increased from 0.05 + // Asymmetric waves that react to mouse position + float wave1 = sin(pos.x * 3.0 + u_time * 1.2 + mouseOffset.x * 2.0) * cos(pos.y * 2.5 - u_time * 0.8) * 0.12; + float wave2 = cos(pos.y * 4.0 - u_time * 1.5 + mouseOffset.y * 2.0) * sin(pos.z * 3.0 + u_time) * 0.1; + float wave3 = sin(length(pos.xz) * 5.0 - u_time * 2.0 - mouseDistance * 4.0) * 0.08; - // Circular wave patterns for ripple effect - float distFromCenter = length(position.xy); - displacement += sin(distFromCenter * 8.0 - u_time * 3.0) * 0.05; - displacement += cos(distFromCenter * 4.0 + u_time * 2.0) * 0.04; + // Spike-like protrusions that follow mouse + float spikes = pow(sin(angle * 8.0 + u_time * 0.5 - atan(mouseOffset.y, mouseOffset.x)), 4.0) * 0.15; + spikes *= smoothstep(0.3, 0.7, sin(pos.z * 4.0 + u_time)); - // Add frequency-like animation without audio - float simulatedFreq = sin(u_time * 0.5) * 0.5 + 0.5; - displacement += simulatedFreq * 0.1; // Reduced from 0.15 + // Turbulent noise for organic chaos + float noise = snoise(pos * 1.2 + u_time * 0.3 + vec3(mouseOffset, 0.0)) * 0.08; + noise += snoise(pos * 2.5 - u_time * 0.4) * 0.05; + noise += snoise(pos * 5.0 + u_time * 0.6) * 0.03; - // Mouse influence on displacement - keep this subtle - vec2 mouseInfluence = u_mouse - 0.5; - float mouseDistance = length(mouseInfluence); - float mouseEffect = smoothstep(1.0, 0.0, mouseDistance) * 0.2; + // Combine all deformations + float totalDisplacement = hex + wave1 + wave2 + wave3 + spikes + noise; - // Apply mouse distortion to create waves that follow the mouse - displacement += mouseEffect * sin(position.x * 8.0 - u_time * 2.0 + mouseInfluence.x * 3.0) * 0.05; - displacement += mouseEffect * sin(position.y * 8.0 - u_time * 2.0 + mouseInfluence.y * 3.0) * 0.05; - displacement += mouseEffect * sin(position.z * 8.0 - u_time * 2.0) * 0.03; + // Pulsing with variation + float breathing = sin(u_time * 0.7) * 0.03 + sin(u_time * 1.3) * 0.02 + 1.0; - vDisplacement = displacement; + pos *= breathing * u_scale; + pos += normal * totalDisplacement * u_scale; - vec3 newPosition = position + normal * displacement; - gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0); + vNoise = totalDisplacement; + + gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0); } `; const fragmentShader = ` -uniform float u_red; -uniform float u_green; -uniform float u_blue; uniform float u_time; uniform vec2 u_mouse; - -varying vec2 vUv; -varying float vDisplacement; +varying vec3 vNormal; +varying vec3 vPosition; +varying float vNoise; void main() { - // Create dynamic color based on displacement and time - float intensity = pow(vDisplacement + 0.5, 2.0); + vec3 viewDirection = normalize(cameraPosition - vPosition); + + // Enhanced fresnel for glow + float fresnel = dot(viewDirection, vNormal); + float rimLight = 1.0 - abs(fresnel); + rimLight = pow(rimLight, 1.2); - // Mouse influence on color intensity - vec2 mouseInfluence = u_mouse - 0.5; - float mouseDistance = length(mouseInfluence); - float mouseGlow = smoothstep(1.0, 0.0, mouseDistance) * 0.1; + // Mouse influence on colors + vec2 mouseOffset = u_mouse - 0.5; + float mouseDistance = length(mouseOffset); - vec3 color = vec3(u_red, u_green, u_blue); + // Dynamic color palette that shifts based on deformation and mouse + vec3 color1 = vec3(0.1, 0.9, 0.4); // Bright green + vec3 color2 = vec3(0.0, 0.7, 0.5); // Teal accent + vec3 color3 = vec3(0.3, 1.0, 0.3); // Electric green - // Add color variation based on position and time - color.r *= 0.8 + sin(vUv.x * 10.0 + u_time) * 0.2; - color.g *= 0.8 + sin(vUv.y * 10.0 + u_time * 1.2) * 0.2 + mouseGlow; - color.b *= 0.8 + sin((vUv.x + vUv.y) * 10.0 + u_time * 1.5) * 0.2; + // Color based on deformation intensity and mouse proximity + float deformIntensity = abs(vNoise) * 5.0; + vec3 baseColor = mix(color1, color2, sin(deformIntensity + u_time * 0.5) * 0.5 + 0.5); + baseColor = mix(baseColor, color3, smoothstep(0.1, 0.3, abs(vNoise))); - color *= intensity * (1.0 + mouseGlow); + // Extra glow where stretched towards mouse + float stretchGlow = smoothstep(0.3, 0.7, dot(normalize(vPosition), normalize(vec3(mouseOffset, 0.0)))); + baseColor += vec3(0.1, 0.3, 0.2) * stretchGlow * 0.3; - gl_FragColor = vec4(color, 1.0); + // Holographic interference patterns + float interference = sin(vPosition.x * 15.0 + u_time) * sin(vPosition.y * 15.0 - u_time * 0.7); + interference *= 0.1 * rimLight; + baseColor += vec3(interference * 0.2, interference * 0.5, interference * 0.3); + + // Electric rim effect enhanced by mouse proximity + float electricRim = pow(rimLight, 0.5); + vec3 electricColor = vec3(0.4, 1.0, 0.6); + float electric = sin(atan(vPosition.y, vPosition.x) * 20.0 + u_time * 3.0) * electricRim; + electric = smoothstep(0.6, 1.0, electric) * 0.3; + electric *= 1.0 + (1.0 - mouseDistance) * 0.5; + + // Core energy with color variation + float centerDistance = length(vPosition) / 2.2; + float coreGlow = smoothstep(1.0, 0.0, centerDistance) * 0.4; + vec3 coreColor = mix(vec3(0.5, 1.0, 0.7), vec3(0.3, 0.8, 1.0), sin(u_time * 1.5) * 0.5 + 0.5); + + // Combine all effects + vec3 finalColor = baseColor; + finalColor += electricColor * electric; + finalColor += coreColor * coreGlow; + finalColor += electricColor * electricRim * 0.5; + + // Energy fluctuations + float fluctuation = sin(u_time * 4.0 + vPosition.z * 10.0) * 0.1 + 0.9; + finalColor *= fluctuation; + + // Dynamic alpha + float alpha = 0.2 + rimLight * 0.35 + coreGlow * 0.2 + electric * 0.3; + + gl_FragColor = vec4(finalColor, alpha); } `; @@ -167,96 +189,61 @@ interface AnimatedOrbProps { function AnimatedOrb({ scale = 1 }: AnimatedOrbProps) { const meshRef = useRef(null); - const mouseRef = useRef({ x: 0, y: 0 }); - const currentScaleRef = useRef(scale); - const targetScaleRef = useRef(scale); - const pulseRef = useRef(0); + const currentScale = useRef(scale); + const mousePosition = useRef({ x: 0, y: 0 }); const uniforms = useMemo( () => ({ u_time: { value: 0.0 }, - u_frequency: { value: 0.0 }, - u_red: { value: 0.0 }, // Green color has minimal red - u_green: { value: 0.5 }, // Reduced from 0.7 for less brightness - u_blue: { value: 0.2 }, // Reduced from 0.3 + u_scale: { value: 1.0 }, u_mouse: { value: new THREE.Vector2(0.5, 0.5) }, }), [], ); + // Track mouse movement useEffect(() => { const handleMouseMove = (e: MouseEvent) => { - mouseRef.current.x = e.clientX / window.innerWidth; - mouseRef.current.y = 1.0 - e.clientY / window.innerHeight; // Invert Y + mousePosition.current.x = e.clientX / window.innerWidth; + mousePosition.current.y = 1.0 - e.clientY / window.innerHeight; // Invert Y }; window.addEventListener('mousemove', handleMouseMove); return () => window.removeEventListener('mousemove', handleMouseMove); }, []); - // Update target scale when prop changes - useEffect(() => { - // Trigger a pulse when scale changes - if (targetScaleRef.current !== scale) { - pulseRef.current = 1; - } - targetScaleRef.current = scale; - }, [scale]); - useFrame((state) => { if (meshRef.current) { - uniforms.u_time.value = state.clock.getElapsedTime(); - - // Simulate frequency changes with sine waves - uniforms.u_frequency.value = Math.sin(state.clock.getElapsedTime() * 0.5) * 50 + 50; - - // Smoothly update mouse position with slower interpolation - uniforms.u_mouse.value.x += (mouseRef.current.x - uniforms.u_mouse.value.x) * 0.03; - uniforms.u_mouse.value.y += (mouseRef.current.y - uniforms.u_mouse.value.y) * 0.03; - - // Camera follows mouse smoothly with reduced movement - const targetX = (mouseRef.current.x - 0.5) * 1; - const targetY = (mouseRef.current.y - 0.5) * 1; - state.camera.position.x += (targetX - state.camera.position.x) * 0.02; - state.camera.position.y += (targetY - state.camera.position.y) * 0.02; - state.camera.lookAt(0, 0, 0); - - // Rotate the orb based on mouse position with reduced sensitivity - meshRef.current.rotation.y += - ((mouseRef.current.x - 0.5) * 0.5 - meshRef.current.rotation.y) * 0.02; - meshRef.current.rotation.x += - ((mouseRef.current.y - 0.5) * 0.5 - meshRef.current.rotation.x) * 0.02; + const time = state.clock.getElapsedTime(); + uniforms.u_time.value = time; - // Smooth scale transition with easing for non-jumpy growth - // Use an ease-in-out curve for smoother transitions - const scaleDiff = targetScaleRef.current - currentScaleRef.current; - const easeAmount = Math.abs(scaleDiff) > 0.01 ? 0.04 : 0.08; // Slower when far, faster when close - currentScaleRef.current += scaleDiff * easeAmount; + currentScale.current += (scale - currentScale.current) * 0.03; + uniforms.u_scale.value = currentScale.current; - // Decay pulse effect more slowly for better visibility - pulseRef.current *= 0.98; // Even slower decay + // Smooth mouse position updates + uniforms.u_mouse.value.x += (mousePosition.current.x - uniforms.u_mouse.value.x) * 0.05; + uniforms.u_mouse.value.y += (mousePosition.current.y - uniforms.u_mouse.value.y) * 0.05; - // Breathing effect on top of the smooth scale, with very subtle pulse - const breathingScale = - currentScaleRef.current * - (1 + Math.sin(state.clock.getElapsedTime() * 2) * 0.03 + pulseRef.current * 0.03); // Even more subtle - meshRef.current.scale.setScalar(breathingScale); + // Subtle multi-axis rotation influenced by mouse + const mouseInfluenceX = (uniforms.u_mouse.value.x - 0.5) * 0.3; + const mouseInfluenceY = (uniforms.u_mouse.value.y - 0.5) * 0.3; - // Very subtle glow during pulse - uniforms.u_green.value = 0.5 + pulseRef.current * 0.05; // Updated base value to 0.5 + meshRef.current.rotation.y = time * 0.08 + mouseInfluenceX; + meshRef.current.rotation.x = Math.sin(time * 0.05) * 0.15 + mouseInfluenceY; + meshRef.current.rotation.z = Math.cos(time * 0.07) * 0.1; } }); return ( - + ); @@ -268,29 +255,19 @@ interface AnimatedGradientBackgroundProps { export function AnimatedGradientBackground({ scale = 1 }: AnimatedGradientBackgroundProps) { return ( -
+
- - -
); diff --git a/apps/app/src/app/(app)/setup/components/AnimatedGradientBackgroundWrapper.tsx b/apps/app/src/app/(app)/setup/components/AnimatedGradientBackgroundWrapper.tsx new file mode 100644 index 0000000000..fe92333669 --- /dev/null +++ b/apps/app/src/app/(app)/setup/components/AnimatedGradientBackgroundWrapper.tsx @@ -0,0 +1,41 @@ +'use client'; + +import { useEffect, useState } from 'react'; +import { AnimatedGradientBackground } from './AnimatedGradientBackground'; + +export function AnimatedGradientBackgroundWrapper() { + const [scale, setScale] = useState(0.7); + + useEffect(() => { + // Function to calculate scale from localStorage + const updateScale = () => { + if (typeof window !== 'undefined') { + const stepIndex = parseInt(localStorage.getItem('onboarding-step-index') || '0'); + const totalSteps = parseInt(localStorage.getItem('onboarding-total-steps') || '9'); + + // Calculate scale based on step progress (0.7 to 1.5) + const progressScale = 0.7 + (stepIndex / (totalSteps - 1)) * 0.8; + setScale(progressScale); + } + }; + + // Initial load + updateScale(); + + // Listen for step changes + const handleStepChange = (event: Event) => { + const customEvent = event as CustomEvent; + const { stepIndex, totalSteps } = customEvent.detail; + const progressScale = 0.7 + (stepIndex / (totalSteps - 1)) * 0.8; + setScale(progressScale); + }; + + window.addEventListener('onboarding-step-change', handleStepChange); + + return () => { + window.removeEventListener('onboarding-step-change', handleStepChange); + }; + }, []); + + return ; +} diff --git a/apps/app/src/app/(app)/setup/components/OrganizationSetupForm.tsx b/apps/app/src/app/(app)/setup/components/OrganizationSetupForm.tsx index 1a2f2c8575..edaded4d62 100644 --- a/apps/app/src/app/(app)/setup/components/OrganizationSetupForm.tsx +++ b/apps/app/src/app/(app)/setup/components/OrganizationSetupForm.tsx @@ -7,9 +7,8 @@ import { Card, CardContent, CardFooter, CardHeader, CardTitle } from '@comp/ui/c import { Form, FormControl, FormField, FormItem, FormMessage } from '@comp/ui/form'; import { useAction } from 'next-safe-action/hooks'; import { useRouter } from 'next/navigation'; -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import { useOnboardingForm } from '../hooks/useOnboardingForm'; -import { AnimatedGradientBackground } from './AnimatedGradientBackground'; import { OnboardingFormActions } from './OnboardingFormActions'; import { OnboardingStepInput } from './OnboardingStepInput'; @@ -63,80 +62,100 @@ export function OrganizationSetupForm({ const hasExistingOrgs = existingOrganizations.length > 0; - // Calculate scale based on step progress (0.7 to 1.5) - const progressScale = 0.7 + (stepIndex / (steps.length - 1)) * 0.8; + // Save step progress to localStorage + useEffect(() => { + if (typeof window !== 'undefined') { + if (isFinalizing) { + // Set to max scale when finalizing + localStorage.setItem('onboarding-progress', '1'); + window.dispatchEvent( + new CustomEvent('onboarding-step-change', { + detail: { stepIndex: steps.length - 1, totalSteps: steps.length, progress: 1 }, + }), + ); + } else { + const progress = stepIndex / (steps.length - 1); + localStorage.setItem('onboarding-step-index', stepIndex.toString()); + localStorage.setItem('onboarding-total-steps', steps.length.toString()); + localStorage.setItem('onboarding-progress', progress.toString()); + + // Dispatch custom event to notify the background wrapper + window.dispatchEvent( + new CustomEvent('onboarding-step-change', { + detail: { stepIndex, totalSteps: steps.length, progress }, + }), + ); + } + } + }, [stepIndex, steps.length, isFinalizing]); return isFinalizing ? (
-
) : ( - <> - -
-
- - {isLoadingFrameworks && step.key === 'frameworkIds' && ( -
- -
- )} - -
- -
- Step {stepIndex + 1} of {steps.length} -
- - {step.question} - +
+
+ + {isLoadingFrameworks && step.key === 'frameworkIds' && ( +
+ +
+ )} + +
+ +
+ Step {stepIndex + 1} of {steps.length}
- - -
- - ( - - - - -
- -
-
- )} - /> - - -
- -
- {/* Skip button removed - forcing all questions */} -
- -
- -
+ + {step.question} + +
+ + +
+ + ( + + + + +
+ +
+
+ )} + /> + + +
+ +
+ {/* Skip button removed - forcing all questions */} +
+ +
+
- +
); } diff --git a/apps/app/src/app/(app)/setup/layout.tsx b/apps/app/src/app/(app)/setup/layout.tsx index cf2996a3fd..df3969f2e9 100644 --- a/apps/app/src/app/(app)/setup/layout.tsx +++ b/apps/app/src/app/(app)/setup/layout.tsx @@ -3,6 +3,7 @@ import { getOrganizations } from '@/data/getOrganizations'; import { auth } from '@/utils/auth'; import { headers } from 'next/headers'; import { redirect } from 'next/navigation'; +import { AnimatedGradientBackgroundWrapper } from './components/AnimatedGradientBackgroundWrapper'; export default async function SetupLayout({ children }: { children: React.ReactNode }) { const session = await auth.api.getSession({ @@ -18,13 +19,14 @@ export default async function SetupLayout({ children }: { children: React.ReactN return (
+ - {children} +
{children}
); } diff --git a/apps/app/src/app/(app)/setup/loading/[orgId]/page.tsx b/apps/app/src/app/(app)/setup/loading/[orgId]/page.tsx index fe1c7cc8ac..4df98884c2 100644 --- a/apps/app/src/app/(app)/setup/loading/[orgId]/page.tsx +++ b/apps/app/src/app/(app)/setup/loading/[orgId]/page.tsx @@ -1,4 +1,3 @@ -import { AnimatedGradientBackground } from '@/app/(app)/setup/components/AnimatedGradientBackground'; import { SetupLoadingStep } from '@/app/(app)/setup/components/SetupLoadingStep'; import { getOrganizations } from '@/data/getOrganizations'; import { auth } from '@/utils/auth'; @@ -33,10 +32,5 @@ export default async function SetupLoadingPage({ params }: SetupLoadingPageProps console.error('Failed to fetch organizations:', error); } - return ( - <> - - - - ); + return ; } diff --git a/apps/app/src/components/layout/MinimalHeader.tsx b/apps/app/src/components/layout/MinimalHeader.tsx index a731439e3e..7399c5dd72 100644 --- a/apps/app/src/components/layout/MinimalHeader.tsx +++ b/apps/app/src/components/layout/MinimalHeader.tsx @@ -2,7 +2,6 @@ import { changeOrganizationAction } from '@/actions/change-organization'; import { MinimalOrganizationSwitcher } from '@/components/layout/MinimalOrganizationSwitcher'; -import { ThemeSwitch } from '@/components/theme-switch'; import { authClient } from '@/utils/auth-client'; import type { Organization } from '@comp/db/types'; import { Icons } from '@comp/ui/icons'; @@ -85,7 +84,7 @@ export function MinimalHeader({
- + {/* */} {user.email}