| 1 |
import { ExtendifyCodeConnector } from '@auto-launch/components/ExtendifyCodeConnector'; |
| 2 |
import { Launch } from '@auto-launch/components/Launch'; |
| 3 |
import { Logo } from '@auto-launch/components/Logo'; |
| 4 |
import { MigrateChoice } from '@auto-launch/components/MigrateChoice'; |
| 5 |
import { MovingGradient } from '@auto-launch/components/MovingGradients'; |
| 6 |
import { NeedsTheme } from '@auto-launch/components/NeedsTheme'; |
| 7 |
import { RestartLaunchModal } from '@auto-launch/components/RestartLaunchModal'; |
| 8 |
import { ViewportPulse } from '@auto-launch/components/ViewportPulse'; |
| 9 |
import { getAbTest } from '@auto-launch/functions/getAbTest'; |
| 10 |
import { preLaunchFunctions } from '@auto-launch/functions/setup'; |
| 11 |
import { updateOption } from '@auto-launch/functions/wp'; |
| 12 |
import { useLaunchDataStore } from '@auto-launch/state/launch-data'; |
| 13 |
import { registerCoreBlocks } from '@wordpress/block-library'; |
| 14 |
import { getBlockTypes } from '@wordpress/blocks'; |
| 15 |
import { useSelect } from '@wordpress/data'; |
| 16 |
import { useEffect, useRef, useState } from '@wordpress/element'; |
| 17 |
import { __ } from '@wordpress/i18n'; |
| 18 |
import { chevronLeft, Icon } from '@wordpress/icons'; |
| 19 |
import classNames from 'classnames'; |
| 20 |
import { AnimatePresence, motion } from 'framer-motion'; |
| 21 |
import { checkIn, reportRestApiStatus } from './functions/insights'; |
| 22 |
|
| 23 |
export const LaunchPage = () => { |
| 24 |
const theme = useSelect((select) => select('core').getCurrentTheme()); |
| 25 |
// Checking `theme` here makes sure the data is populated |
| 26 |
const needsTheme = theme && theme?.textdomain !== 'extendable'; |
| 27 |
|
| 28 |
const oldPages = window.extLaunchData.resetSiteInformation.pagesIds ?? []; |
| 29 |
const needsToReset = oldPages.length > 0; |
| 30 |
|
| 31 |
const { |
| 32 |
title, |
| 33 |
descriptionRaw, |
| 34 |
go, |
| 35 |
urlParams, |
| 36 |
designBuild, |
| 37 |
setData, |
| 38 |
showExtendifyCodeScreen, |
| 39 |
} = useLaunchDataStore(); |
| 40 |
const skipDescription = |
| 41 |
Boolean(urlParams?.['build-id']) || |
| 42 |
designBuild || |
| 43 |
((title || descriptionRaw) && go); |
| 44 |
const showConnector = !skipDescription && showExtendifyCodeScreen; |
| 45 |
const showExitLink = |
| 46 |
!skipDescription && !window.extLaunchData?.hideAutoLaunchExitLink; |
| 47 |
const inMigrateVariant = |
| 48 |
getAbTest('AutoLaunch.MigrateScreen').variant === 'B'; |
| 49 |
const [choosingMigration, setChoosingMigration] = useState(inMigrateVariant); |
| 50 |
const showMigrateChoice = !skipDescription && choosingMigration; |
| 51 |
|
| 52 |
const containerRef = useRef(null); |
| 53 |
|
| 54 |
useEffect(() => { |
| 55 |
// translators: Launch is a noun. |
| 56 |
document.title = __('Launch - AI-Powered Web Creation', 'extendify-local'); |
| 57 |
updateOption('extendify_launch_loaded', new Date().toISOString()); |
| 58 |
// We load core blocks so we can parse them |
| 59 |
if (getBlockTypes().length === 0) registerCoreBlocks(); |
| 60 |
|
| 61 |
preLaunchFunctions(); |
| 62 |
checkIn({ stage: 'launch_page' }); |
| 63 |
reportRestApiStatus(); |
| 64 |
}, []); |
| 65 |
|
| 66 |
if (needsTheme) { |
| 67 |
return ( |
| 68 |
<Wrapper> |
| 69 |
<div className="bg-white w-full max-w-3xl rounded-lg border border-design-main/60 relative z-10"> |
| 70 |
<NeedsTheme /> |
| 71 |
</div> |
| 72 |
</Wrapper> |
| 73 |
); |
| 74 |
} |
| 75 |
|
| 76 |
if (needsToReset) { |
| 77 |
return ( |
| 78 |
<Wrapper> |
| 79 |
<div className="w-full max-w-2xl rounded-3xl border bg-gray-100/80 backdrop-blur-2xl shadow-md relative z-10 border-gray-300"> |
| 80 |
<RestartLaunchModal pages={oldPages} /> |
| 81 |
</div> |
| 82 |
</Wrapper> |
| 83 |
); |
| 84 |
} |
| 85 |
|
| 86 |
return ( |
| 87 |
<Wrapper |
| 88 |
footer={ |
| 89 |
showConnector ? ( |
| 90 |
<BackLink onClick={() => setData('showExtendifyCodeScreen', false)} /> |
| 91 |
) : showExitLink ? ( |
| 92 |
<ExitLink /> |
| 93 |
) : null |
| 94 |
} |
| 95 |
> |
| 96 |
<AnimatePresence mode="wait" initial={false}> |
| 97 |
<TheTitle |
| 98 |
key={showMigrateChoice ? 'migrate' : 'description'} |
| 99 |
// The connector renders its own heading, so hide the shared one. |
| 100 |
hide={skipDescription || showConnector} |
| 101 |
migrate={showMigrateChoice} |
| 102 |
/> |
| 103 |
</AnimatePresence> |
| 104 |
<div |
| 105 |
ref={containerRef} |
| 106 |
className={classNames('w-full relative z-10', { |
| 107 |
'max-w-3xl': inMigrateVariant || showConnector, |
| 108 |
'max-w-2xl': !inMigrateVariant && !showConnector, |
| 109 |
'md:h-72.75': inMigrateVariant && !skipDescription, |
| 110 |
})} |
| 111 |
> |
| 112 |
<AnimatePresence mode="wait"> |
| 113 |
{showConnector && ( |
| 114 |
<ExtendifyCodeConnector |
| 115 |
key="extendify-code" |
| 116 |
onProceed={() => setData('go', true)} |
| 117 |
/> |
| 118 |
)} |
| 119 |
{!showConnector && showMigrateChoice && ( |
| 120 |
<MigrateChoice |
| 121 |
key="migrate-choice" |
| 122 |
onBuildNew={() => setChoosingMigration(false)} |
| 123 |
/> |
| 124 |
)} |
| 125 |
{!showConnector && !showMigrateChoice && ( |
| 126 |
<Launch |
| 127 |
key={skipDescription ? 'description-launch' : 'creating-launch'} |
| 128 |
skipDescription={skipDescription} |
| 129 |
lastHeight={containerRef.current?.offsetHeight} |
| 130 |
/> |
| 131 |
)} |
| 132 |
</AnimatePresence> |
| 133 |
</div> |
| 134 |
</Wrapper> |
| 135 |
); |
| 136 |
}; |
| 137 |
|
| 138 |
const Wrapper = ({ children, footer }) => { |
| 139 |
const { pulse } = useLaunchDataStore(); |
| 140 |
|
| 141 |
return ( |
| 142 |
<div style={{ zIndex: 99999 + 1 }} className="fixed inset-0 bg-white"> |
| 143 |
<div className="relative h-dvh bg-banner-main text-banner-text text-base overflow-y-auto"> |
| 144 |
<div className="relative z-10 min-h-dvh w-full flex flex-col items-center justify-between p-6"> |
| 145 |
<div className="w-full flex flex-col items-center gap-5 md:gap-8 m-auto"> |
| 146 |
<div className="mb-4"> |
| 147 |
<Logo /> |
| 148 |
</div> |
| 149 |
{children} |
| 150 |
</div> |
| 151 |
{footer && <div className="w-full pt-8 shrink-0">{footer}</div>} |
| 152 |
</div> |
| 153 |
</div> |
| 154 |
<MovingGradient /> |
| 155 |
{pulse ? <ViewportPulse /> : null} |
| 156 |
</div> |
| 157 |
); |
| 158 |
}; |
| 159 |
|
| 160 |
const ExitLink = () => { |
| 161 |
return ( |
| 162 |
<a |
| 163 |
className="inline-flex items-center gap-0.5 text-sm text-banner-text opacity-70 hover:opacity-100 transition-opacity" |
| 164 |
href={window.extSharedData.adminUrl} |
| 165 |
onClick={() => checkIn({ stage: 'exit_to_wp_admin' })} |
| 166 |
> |
| 167 |
<Icon fill="currentColor" icon={chevronLeft} size={20} /> |
| 168 |
{__('WP Admin Dashboard', 'extendify-local')} |
| 169 |
</a> |
| 170 |
); |
| 171 |
}; |
| 172 |
|
| 173 |
const BackLink = ({ onClick }) => { |
| 174 |
return ( |
| 175 |
<button |
| 176 |
type="button" |
| 177 |
onClick={onClick} |
| 178 |
className="inline-flex items-center gap-0.5 border-0 bg-transparent cursor-pointer text-sm text-banner-text opacity-70 hover:opacity-100 transition-opacity" |
| 179 |
> |
| 180 |
<Icon fill="currentColor" icon={chevronLeft} size={20} /> |
| 181 |
{__('Back', 'extendify-local')} |
| 182 |
</button> |
| 183 |
); |
| 184 |
}; |
| 185 |
|
| 186 |
const TheTitle = ({ hide, migrate }) => { |
| 187 |
const useOldHeader = |
| 188 |
getAbTest('AutoLaunch.HeaderParagraphOld').variant === 'B'; |
| 189 |
if (hide) return null; |
| 190 |
|
| 191 |
const headingClass = |
| 192 |
'text-xl md:text-2xl text-pretty text-banner-text font-semibold p-0 m-0 text-center'; |
| 193 |
const transition = { |
| 194 |
animate: { opacity: 1 }, |
| 195 |
exit: { opacity: 0 }, |
| 196 |
transition: { duration: 0.4 }, |
| 197 |
}; |
| 198 |
|
| 199 |
if (migrate) { |
| 200 |
return ( |
| 201 |
<motion.h2 className={headingClass} {...transition}> |
| 202 |
{__('How would you like to start your website?', 'extendify-local')} |
| 203 |
</motion.h2> |
| 204 |
); |
| 205 |
} |
| 206 |
|
| 207 |
if (useOldHeader) { |
| 208 |
return ( |
| 209 |
<motion.div className="flex flex-col items-center gap-2" {...transition}> |
| 210 |
<h2 className={headingClass}> |
| 211 |
{__('Tell Us About Your Website', 'extendify-local')} |
| 212 |
</h2> |
| 213 |
<p className="text-sm md:text-base text-pretty text-banner-text opacity-70 p-0 m-0 text-center max-w-xl"> |
| 214 |
{__( |
| 215 |
"Share your vision, and we'll craft a website that's perfectly tailored to your needs, ready to launch in no time.", |
| 216 |
'extendify-local', |
| 217 |
)} |
| 218 |
</p> |
| 219 |
</motion.div> |
| 220 |
); |
| 221 |
} |
| 222 |
|
| 223 |
return ( |
| 224 |
<motion.h2 className={headingClass} {...transition}> |
| 225 |
{__('Describe the website you want to build', 'extendify-local')} |
| 226 |
</motion.h2> |
| 227 |
); |
| 228 |
}; |
| 229 |
|