'use client' import { Fragment, useEffect, useId, useRef, useState } from 'react' import { Tab, TabGroup, TabList, TabPanel, TabPanels } from '@headlessui/react' import clsx from 'clsx' import { type MotionProps, type Variant, type Variants, AnimatePresence, motion, } from 'framer-motion' import { useDebouncedCallback } from 'use-debounce' import { AppScreen } from '@/components/AppScreen' import { CircleBackground } from '@/components/CircleBackground' import { Container } from '@/components/Container' import { PhoneFrame } from '@/components/PhoneFrame' import { DiageoLogo, LaravelLogo, MirageLogo, ReversableLogo, StatamicLogo, StaticKitLogo, TransistorLogo, TupleLogo, } from '@/components/StockLogos' const MotionAppScreenHeader = motion(AppScreen.Header) const MotionAppScreenBody = motion(AppScreen.Body) interface CustomAnimationProps { isForwards: boolean changeCount: number } const features = [ { name: 'Invite friends for better returns', description: 'For every friend you invite to EngageOS, you get insider notifications 5 seconds sooner. And it’s 10 seconds if you invite an insider.', icon: DeviceUserIcon, screen: InviteScreen, }, { name: 'Notifications on stock dips', description: 'Get a push notification every time we find out something that’s going to lower the share price on your holdings so you can sell before the information hits the public markets.', icon: DeviceNotificationIcon, screen: StocksScreen, }, { name: 'Invest what you want', description: 'We hide your stock purchases behind thousands of anonymous trading accounts, so suspicious activity can never be traced back to you.', icon: DeviceTouchIcon, screen: InvestScreen, }, ] function DeviceUserIcon(props: React.ComponentPropsWithoutRef<'svg'>) { return ( ) } function DeviceNotificationIcon(props: React.ComponentPropsWithoutRef<'svg'>) { return ( ) } function DeviceTouchIcon(props: React.ComponentPropsWithoutRef<'svg'>) { let id = useId() return ( ) } const headerAnimation: Variants = { initial: { opacity: 0, transition: { duration: 0.3 } }, animate: { opacity: 1, transition: { duration: 0.3, delay: 0.3 } }, exit: { opacity: 0, transition: { duration: 0.3 } }, } const maxZIndex = 2147483647 const bodyVariantBackwards: Variant = { opacity: 0.4, scale: 0.8, zIndex: 0, filter: 'blur(4px)', transition: { duration: 0.4 }, } const bodyVariantForwards: Variant = (custom: CustomAnimationProps) => ({ y: '100%', zIndex: maxZIndex - custom.changeCount, transition: { duration: 0.4 }, }) const bodyAnimation: MotionProps = { initial: 'initial', animate: 'animate', exit: 'exit', variants: { initial: (custom: CustomAnimationProps, ...props) => custom.isForwards ? bodyVariantForwards(custom, ...props) : bodyVariantBackwards, animate: (custom: CustomAnimationProps) => ({ y: '0%', opacity: 1, scale: 1, zIndex: maxZIndex / 2 - custom.changeCount, filter: 'blur(0px)', transition: { duration: 0.4 }, }), exit: (custom: CustomAnimationProps, ...props) => custom.isForwards ? bodyVariantBackwards : bodyVariantForwards(custom, ...props), }, } type ScreenProps = | { animated: true custom: CustomAnimationProps } | { animated?: false } function InviteScreen(props: ScreenProps) { return ( Invite people Get tips 5s sooner for every invite.
{[ { label: 'Full name', value: 'Albert H. Wiggin' }, { label: 'Email address', value: 'awiggin@chase.com' }, ].map((field) => (
{field.label}
{field.value}
))}
Invite person
) } function StocksScreen(props: ScreenProps) { return ( Stocks March 9, 2022
{[ { name: 'Laravel', price: '4,098.01', change: '+4.98%', color: '#F9322C', logo: LaravelLogo, }, { name: 'Tuple', price: '5,451.10', change: '-3.38%', color: '#5A67D8', logo: TupleLogo, }, { name: 'Transistor', price: '4,098.41', change: '+6.25%', color: '#2A5B94', logo: TransistorLogo, }, { name: 'Diageo', price: '250.65', change: '+1.25%', color: '#3320A7', logo: DiageoLogo, }, { name: 'StaticKit', price: '250.65', change: '-3.38%', color: '#2A3034', logo: StaticKitLogo, }, { name: 'Statamic', price: '5,040.85', change: '-3.11%', color: '#0EA5E9', logo: StatamicLogo, }, { name: 'Mirage', price: '140.44', change: '+9.09%', color: '#16A34A', logo: MirageLogo, }, { name: 'Reversable', price: '550.60', change: '-1.25%', color: '#8D8D8D', logo: ReversableLogo, }, ].map((stock) => (
{stock.name}
{stock.price}
{stock.change}
))}
) } function InvestScreen(props: ScreenProps) { return ( Buy $LA $34.28 per share
{[ { label: 'Number of shares', value: '100' }, { label: 'Current market price', value: (
$34.28
), }, { label: 'Estimated cost', value: '$3,428.00' }, ].map((item) => (
{item.label}
{item.value}
))}
Buy shares
) } function usePrevious(value: T) { let ref = useRef() useEffect(() => { ref.current = value }, [value]) return ref.current } function FeaturesDesktop() { let [changeCount, setChangeCount] = useState(0) let [selectedIndex, setSelectedIndex] = useState(0) let prevIndex = usePrevious(selectedIndex) let isForwards = prevIndex === undefined ? true : selectedIndex > prevIndex let onChange = useDebouncedCallback( (selectedIndex) => { setSelectedIndex(selectedIndex) setChangeCount((changeCount) => changeCount + 1) }, 100, { leading: true }, ) return ( {features.map((feature, featureIndex) => (
{featureIndex === selectedIndex && ( )}

{feature.name}

{feature.description}

))}
{features.map((feature, featureIndex) => selectedIndex === featureIndex ? ( ) : null, )}
) } function FeaturesMobile() { let [activeIndex, setActiveIndex] = useState(0) let slideContainerRef = useRef>(null) let slideRefs = useRef>>([]) useEffect(() => { let observer = new window.IntersectionObserver( (entries) => { for (let entry of entries) { if (entry.isIntersecting && entry.target instanceof HTMLDivElement) { setActiveIndex(slideRefs.current.indexOf(entry.target)) break } } }, { root: slideContainerRef.current, threshold: 0.6, }, ) for (let slide of slideRefs.current) { if (slide) { observer.observe(slide) } } return () => { observer.disconnect() } }, [slideContainerRef, slideRefs]) return ( <>
{features.map((feature, featureIndex) => (
ref && (slideRefs.current[featureIndex] = ref)} className="w-full flex-none snap-center px-4 sm:px-6" >

{feature.name}

{feature.description}

))}
{features.map((_, featureIndex) => ( ))}
) } export function PrimaryFeatures() { return (

Every feature you need to win. Try it for yourself.

EngageOS was built for investors like you who play by their own rules and aren’t going to let SEC regulations get in the way of their dreams. If other investing tools are afraid to build it, EngageOS has it.

) }