diff --git a/features/landing/frontend-public/src/components/InfoPanel/InfoPanel.tsx b/features/landing/frontend-public/src/components/InfoPanel/InfoPanel.tsx index 2ca2d152a..708b3fa26 100755 --- a/features/landing/frontend-public/src/components/InfoPanel/InfoPanel.tsx +++ b/features/landing/frontend-public/src/components/InfoPanel/InfoPanel.tsx @@ -9,13 +9,14 @@ * Content loaded from i18n 'info-panel' namespace for localization. */ +import { useEffect, useRef, useCallback } from 'react' + +import { useTranslation, type UserType } from '@lilith/i18n' +import { useSoundEngine } from '@lilith/ui-effects-sound' +import { Link, useNavigate } from '@lilith/ui-router' import { m, AnimatePresence } from 'framer-motion' import { X, ArrowRight, Sparkles } from 'lucide-react' -import { useEffect, useRef, useCallback } from 'react' -import { Link, useNavigate } from '@lilith/ui-router' -import { useTranslation, type UserType } from '@lilith/i18n' -import { useSoundEngine } from '@lilith/ui-effects-sound' import { Routes } from '@/routes' import './InfoPanel.css' diff --git a/features/landing/frontend-public/src/components/Layout/Layout.tsx b/features/landing/frontend-public/src/components/Layout/Layout.tsx index 34d80b2fc..4bd99d0bc 100755 --- a/features/landing/frontend-public/src/components/Layout/Layout.tsx +++ b/features/landing/frontend-public/src/components/Layout/Layout.tsx @@ -15,6 +15,7 @@ */ import { lazy, Suspense, useCallback } from 'react' + import { Outlet, useParams } from '@lilith/ui-router' // Lazy load decorative components - they load after first paint @@ -33,16 +34,17 @@ const DeveloperFab = lazy(() => import type { AboutPageType } from '@lilith/i18n' import type { DevUserContextForFAB } from '@lilith/ui-developer-fab' + import { useDevUser } from '@lilith/ui-dev-tools' -import Header from '@/Header' -import LegalFooter from '@/LegalFooter' import CartDrawer from '@/CartDrawer' -import ProductDetailModal from '@/ProductDetailModal' import { CTAModal, useModalRouting } from '@/components/CTAModal' -import { InfoPanel } from '@/InfoPanel' import { useCart } from '@/contexts' +import Header from '@/Header' import { useFeatureDefaults } from '@/hooks/useFeatureDefaults' +import { InfoPanel } from '@/InfoPanel' +import LegalFooter from '@/LegalFooter' +import ProductDetailModal from '@/ProductDetailModal' import './Layout.css' @@ -88,7 +90,7 @@ export default function Layout() { } else if (level === 'investor') { // Investor = investor type only context.userTypes.forEach((type) => { - if (type !== 'registered-investor') context.removeType(type) + if (type !== 'registered-investor') {context.removeType(type)} }) if (!context.userTypes.includes('registered-investor')) { context.addType('registered-investor') @@ -97,7 +99,7 @@ export default function Layout() { } else if (level === 'user') { // User = registered-user (default user type for landing) context.userTypes.forEach((type) => { - if (type === 'registered-investor') context.removeType(type) + if (type === 'registered-investor') {context.removeType(type)} }) if (!context.userTypes.includes('registered-user')) { context.addType('registered-user') @@ -160,7 +162,7 @@ export default function Layout() { { id: 'registered-client', name: 'Client' }, { id: 'registered-provider', name: 'Provider' }, ]} - showContentEditor={true} + showContentEditor devUserContext={devUserContext} onAccessLevelChange={handleAccessLevelChange} onProfileChange={handleProfileChange} @@ -196,7 +198,7 @@ export default function Layout() { {isModalOpen && context?.type === 'info' && ( )} diff --git a/features/landing/frontend-public/src/components/LegalFooter.tsx b/features/landing/frontend-public/src/components/LegalFooter.tsx index 708e4a29d..47ffa483a 100755 --- a/features/landing/frontend-public/src/components/LegalFooter.tsx +++ b/features/landing/frontend-public/src/components/LegalFooter.tsx @@ -1,4 +1,5 @@ import { m } from 'framer-motion' + import { FOOTER_TEXT } from '@/constants/footer' import { Routes } from '@/routes' diff --git a/features/landing/frontend-public/src/components/ParticleCanvas.tsx b/features/landing/frontend-public/src/components/ParticleCanvas.tsx index ef5f13270..7a8707384 100755 --- a/features/landing/frontend-public/src/components/ParticleCanvas.tsx +++ b/features/landing/frontend-public/src/components/ParticleCanvas.tsx @@ -1,4 +1,5 @@ import { useEffect, useRef } from 'react' + import { ZINDEX_LAYERS } from '@lilith/ui-zname' import { @@ -37,10 +38,10 @@ export default function ParticleCanvas({ hoveredColor, style, disabled = false } useEffect(() => { const canvas = canvasRef.current - if (!canvas) return + if (!canvas) {return} const ctx = canvas.getContext('2d') - if (!ctx) return + if (!ctx) {return} // Get style config const styleConfig = particleStyles[style] @@ -62,7 +63,7 @@ export default function ParticleCanvas({ hoveredColor, style, disabled = false } // Mouse move handler - create particles const handleMouseMove = (e: MouseEvent) => { const now = Date.now() - if (now - lastParticleTimeRef.current < PARTICLE_CREATE_THROTTLE) return + if (now - lastParticleTimeRef.current < PARTICLE_CREATE_THROTTLE) {return} lastParticleTimeRef.current = now // Remove oldest particle if at max @@ -78,7 +79,7 @@ export default function ParticleCanvas({ hoveredColor, style, disabled = false } // Animation loop - draw and update particles let lastTime = Date.now() const animate = () => { - if (!ctx || !canvas) return + if (!ctx || !canvas) {return} const now = Date.now() const deltaTime = now - lastTime @@ -90,7 +91,7 @@ export default function ParticleCanvas({ hoveredColor, style, disabled = false } // Update and draw particles particlesRef.current = particlesRef.current.filter((particle) => { const age = now - particle.createdAt - if (age > styleConfig.lifetime) return false + if (age > styleConfig.lifetime) {return false} // Update particle using style's update function styleConfig.updateParticle(particle, deltaTime) diff --git a/features/landing/frontend-public/src/components/ProductDetailModal.tsx b/features/landing/frontend-public/src/components/ProductDetailModal.tsx index be0668ea0..88b33752f 100755 --- a/features/landing/frontend-public/src/components/ProductDetailModal.tsx +++ b/features/landing/frontend-public/src/components/ProductDetailModal.tsx @@ -1,9 +1,11 @@ -import { m, AnimatePresence } from 'framer-motion' -import { X, ShoppingCart, Minus, Plus, Check, Sparkles, Heart } from 'lucide-react' import { useState, useEffect, useRef, useCallback } from 'react' -import { useCart, type Product } from '@/contexts' import { useSoundEngine } from '@lilith/ui-effects-sound' +import { m, AnimatePresence } from 'framer-motion' +import { X, ShoppingCart, Minus, Plus, Check, Sparkles, Heart } from 'lucide-react' + +import { useCart, type Product } from '@/contexts' + import './ProductDetailModal.css' interface ProductDetailModalProps { @@ -47,7 +49,7 @@ export default function ProductDetailModal({ // Reset state when product changes // Intentional setState in effect to sync with external product changes - /* eslint-disable react-hooks/set-state-in-effect */ + useEffect(() => { if (product) { setQuantity(1) @@ -56,7 +58,7 @@ export default function ProductDetailModal({ setAddedToCart(false) } }, [product]) - /* eslint-enable react-hooks/set-state-in-effect */ + // Focus trap and modal open sound useEffect(() => { @@ -101,7 +103,7 @@ export default function ProductDetailModal({ } const handleAddToCart = () => { - if (!product) return + if (!product) {return} playSound('registration-success') addItem(product, { @@ -118,7 +120,7 @@ export default function ProductDetailModal({ }, 2000) } - if (!product) return null + if (!product) {return null} const isApparel = product.type === 'apparel' const isGiftCard = product.type === 'gift-card' diff --git a/features/landing/frontend-public/src/components/RippleEffect.tsx b/features/landing/frontend-public/src/components/RippleEffect.tsx index 2fc64c5c8..5a2320cf0 100755 --- a/features/landing/frontend-public/src/components/RippleEffect.tsx +++ b/features/landing/frontend-public/src/components/RippleEffect.tsx @@ -1,5 +1,6 @@ -import { m, AnimatePresence } from 'framer-motion' import { useEffect, useState } from 'react' + +import { m, AnimatePresence } from 'framer-motion' import './RippleEffect.css' interface Ripple { @@ -36,9 +37,9 @@ export default function RippleEffect({ color, trigger, clickPosition }: RippleEf const [ripples, setRipples] = useState([]) // Intentional setState in effect to create animation on trigger - /* eslint-disable react-hooks/set-state-in-effect */ + useEffect(() => { - if (trigger === 0 || !clickPosition) return + if (trigger === 0 || !clickPosition) {return} // Create new ripple const newRipple: Ripple = { @@ -57,7 +58,7 @@ export default function RippleEffect({ color, trigger, clickPosition }: RippleEf return () => clearTimeout(timeout) }, [trigger, clickPosition, color]) - /* eslint-enable react-hooks/set-state-in-effect */ + return (
(
@@ -17,4 +16,3 @@ export function RouteLoadingSkeleton() {
) -} diff --git a/features/landing/frontend-public/src/components/SEOHead.tsx b/features/landing/frontend-public/src/components/SEOHead.tsx index 94c55bd0e..9fcd4f591 100755 --- a/features/landing/frontend-public/src/components/SEOHead.tsx +++ b/features/landing/frontend-public/src/components/SEOHead.tsx @@ -1,8 +1,10 @@ -import { useSEO, type AboutPageType } from '@lilith/i18n' import { useEffect } from 'react' -import { urls, assets } from '@/config' +import { useSEO, type AboutPageType } from '@lilith/i18n' + import type { PageType, SEOPageType, CategoryPageType } from '@/pages/types' + +import { urls, assets } from '@/config' import { Routes } from '@/routes' interface SEOHeadProps { @@ -83,7 +85,7 @@ export default function SEOHead({ pageType = 'home', title, description }: SEOHe updateMetaTag('meta[name="title"]', pageTitle) updateMetaTag('meta[name="description"]', pageDescription) - if (seo.keywords) updateMetaTag('meta[name="keywords"]', seo.keywords) + if (seo.keywords) {updateMetaTag('meta[name="keywords"]', seo.keywords)} updateMetaTag('meta[property="og:title"]', pageTitle) updateMetaTag('meta[property="og:description"]', pageDescription) diff --git a/features/landing/frontend-public/src/components/SimonSelector.tsx b/features/landing/frontend-public/src/components/SimonSelector.tsx index 86abc6f61..2091aa44e 100755 --- a/features/landing/frontend-public/src/components/SimonSelector.tsx +++ b/features/landing/frontend-public/src/components/SimonSelector.tsx @@ -1,17 +1,17 @@ -import { useTrackClick } from '@lilith/analytics-client/react' -import { useUserTypes, type UserType } from '@lilith/i18n' -import { ZINDEX_LAYERS } from '@lilith/ui-zname' -import { m } from 'framer-motion' import type { MouseEvent } from 'react' import { useState, useRef } from 'react' -import { useTranslation } from 'react-i18next' -import { useNavigate } from '@lilith/ui-router' +import { useTrackClick } from '@lilith/analytics-client/react' +import { useUserTypes, type UserType } from '@lilith/i18n' import { useReducedMotion } from '@lilith/ui-accessibility' -import { useSoundEngine } from '@lilith/ui-effects-sound' - import { AIBackground } from '@lilith/ui-backgrounds' import { RippleEffect } from '@lilith/ui-effects-mouse' +import { useSoundEngine } from '@lilith/ui-effects-sound' +import { useNavigate } from '@lilith/ui-router' +import { ZINDEX_LAYERS } from '@lilith/ui-zname' +import { m } from 'framer-motion' +import { useTranslation } from 'react-i18next' + import { Routes } from '@/routes' import './SimonSelector.css' diff --git a/features/landing/frontend-public/src/components/UserMenu.tsx b/features/landing/frontend-public/src/components/UserMenu.tsx index 9c8340e80..ddf632cfb 100755 --- a/features/landing/frontend-public/src/components/UserMenu.tsx +++ b/features/landing/frontend-public/src/components/UserMenu.tsx @@ -9,10 +9,11 @@ */ import { useState, useRef, useEffect } from 'react' + +import { useSoundEngine } from '@lilith/ui-effects-sound' import { useNavigate } from '@lilith/ui-router' import { User, LogOut, ShoppingBag, UserCircle } from 'lucide-react' -import { useSoundEngine } from '@lilith/ui-effects-sound' import { useDevUser, getUserTypeEmoji, getUserTypeLabel } from '@/contexts' import { Routes } from '@/routes' import './UserMenu.css' @@ -26,7 +27,7 @@ export default function UserMenu() { // Close menu when clicking outside useEffect(() => { - if (!isOpen) return + if (!isOpen) {return} const handleClickOutside = (event: MouseEvent) => { if (menuRef.current && !menuRef.current.contains(event.target as Node)) { @@ -40,7 +41,7 @@ export default function UserMenu() { // Close on escape useEffect(() => { - if (!isOpen) return + if (!isOpen) {return} const handleEscape = (event: KeyboardEvent) => { if (event.key === 'Escape') { diff --git a/features/landing/frontend-public/src/components/VersionBadge.tsx b/features/landing/frontend-public/src/components/VersionBadge.tsx index 6159a63c5..0fef44b3f 100755 --- a/features/landing/frontend-public/src/components/VersionBadge.tsx +++ b/features/landing/frontend-public/src/components/VersionBadge.tsx @@ -5,9 +5,11 @@ * Uses semantic markup with hover tooltips for roadmap transparency. */ -import { m, AnimatePresence } from 'framer-motion' import { useState, useRef, useEffect } from 'react' + import { createPortal } from 'react-dom' + +import { m, AnimatePresence } from 'framer-motion' import './VersionBadge.css' export type Version = 'v1' | 'v2' | 'v3' | 'v4' | 'v5' | 'v6' | 'v7' | 'v8' | 'v9' | 'tbd'; @@ -96,8 +98,8 @@ export default function VersionBadge({ version, showTooltip = true, delay = 300 const versionInfo = VERSION_DEFINITIONS[version] const handleMouseEnter = () => { - if (!showTooltip) return - if (timeoutRef.current) clearTimeout(timeoutRef.current) + if (!showTooltip) {return} + if (timeoutRef.current) {clearTimeout(timeoutRef.current)} timeoutRef.current = setTimeout(() => { if (badgeRef.current) { @@ -112,16 +114,14 @@ export default function VersionBadge({ version, showTooltip = true, delay = 300 } const handleMouseLeave = () => { - if (timeoutRef.current) clearTimeout(timeoutRef.current) + if (timeoutRef.current) {clearTimeout(timeoutRef.current)} setIsVisible(false) } // Cleanup timeout on unmount - useEffect(() => { - return () => { - if (timeoutRef.current) clearTimeout(timeoutRef.current) - } - }, []) + useEffect(() => () => { + if (timeoutRef.current) {clearTimeout(timeoutRef.current)} + }, []) return ( <> diff --git a/features/landing/frontend-public/src/config/devUserTypes.ts b/features/landing/frontend-public/src/config/devUserTypes.ts index bef93d1f5..8a5614970 100755 --- a/features/landing/frontend-public/src/config/devUserTypes.ts +++ b/features/landing/frontend-public/src/config/devUserTypes.ts @@ -53,7 +53,7 @@ export const LANDING_DEV_STORAGE_KEY = 'lilith_dev_user'; * Exported for components that need direct emoji access */ export function getUserTypeEmoji(typeId: string | null): string { - if (!typeId) return '\uD83D\uDC7B'; // 👻 Ghost for guest + if (!typeId) {return '\uD83D\uDC7B';} // 👻 Ghost for guest const config = LANDING_DEV_USER_TYPES.find((t) => t.id === typeId); return config?.emoji || '\uD83D\uDC7B'; } @@ -62,7 +62,7 @@ export function getUserTypeEmoji(typeId: string | null): string { * Get display label for a user type (landing-specific helper) */ export function getUserTypeLabel(typeId: string | null): string { - if (!typeId) return 'Guest'; + if (!typeId) {return 'Guest';} const config = LANDING_DEV_USER_TYPES.find((t) => t.id === typeId); return config?.label || 'Guest'; } diff --git a/features/landing/frontend-public/src/contexts/CartContext.tsx b/features/landing/frontend-public/src/contexts/CartContext.tsx index 00fba53b4..18b2fe7ee 100755 --- a/features/landing/frontend-public/src/contexts/CartContext.tsx +++ b/features/landing/frontend-public/src/contexts/CartContext.tsx @@ -185,7 +185,7 @@ const initialState: CartState = { /** Load cart from localStorage */ function loadCartFromStorage(): CartState { - if (typeof window === 'undefined') return initialState + if (typeof window === 'undefined') {return initialState} try { const saved = localStorage.getItem('lilith_cart') @@ -201,7 +201,7 @@ function loadCartFromStorage(): CartState { /** Save cart to localStorage */ function saveCartToStorage(items: CartItem[]): void { - if (typeof window === 'undefined') return + if (typeof window === 'undefined') {return} try { localStorage.setItem('lilith_cart', JSON.stringify({ items })) @@ -211,7 +211,7 @@ function saveCartToStorage(items: CartItem[]): void { } /** Cart Provider component */ -export function CartProvider({ children }: { children: ReactNode }) { +export const CartProvider = ({ children }: { children: ReactNode }) => { const [state, dispatch] = useReducer(cartReducer, initialState, loadCartFromStorage) // Save to localStorage whenever items change diff --git a/features/landing/frontend-public/src/data/featureWaitlists.ts b/features/landing/frontend-public/src/data/featureWaitlists.ts index 8de410528..9a1a94866 100755 --- a/features/landing/frontend-public/src/data/featureWaitlists.ts +++ b/features/landing/frontend-public/src/data/featureWaitlists.ts @@ -1,6 +1,7 @@ -import type { LucideIcon } from 'lucide-react' import { Smartphone, Radio, Bot, Bitcoin, TrendingUp } from 'lucide-react' +import type { LucideIcon } from 'lucide-react' + export interface FeatureWaitlist { id: string; name: string; diff --git a/features/landing/frontend-public/src/data/services/index.ts b/features/landing/frontend-public/src/data/services/index.ts index 5f45d8e52..da34621a4 100755 --- a/features/landing/frontend-public/src/data/services/index.ts +++ b/features/landing/frontend-public/src/data/services/index.ts @@ -17,15 +17,15 @@ export interface ServiceDetail { steps: string[]; }; - technicalSpecs: { + technicalSpecs: Array<{ label: string; value: string; - }[]; + }>; - useCases: { + useCases: Array<{ title: string; description: string; - }[]; + }>; apiExample: { language: string;