| 1 |
import { useEffect, useState, useCallback, useRef } from '@wordpress/element' |
| 2 |
import { __ } from '@wordpress/i18n' |
| 3 |
import { Transition } from '@headlessui/react' |
| 4 |
import { |
| 5 |
installPlugin, |
| 6 |
updateTemplatePart, |
| 7 |
addLaunchPagesToNav, |
| 8 |
updateOption, |
| 9 |
} from '@onboarding/api/WPApi' |
| 10 |
import { useConfetti } from '@onboarding/hooks/useConfetti' |
| 11 |
import { useWarnOnLeave } from '@onboarding/hooks/useWarnOnLeave' |
| 12 |
import { runAtLeastFor } from '@onboarding/lib/util' |
| 13 |
import { |
| 14 |
createWordpressPages, |
| 15 |
trashWordpressPages, |
| 16 |
updateGlobalStyleVariant, |
| 17 |
} from '@onboarding/lib/wp' |
| 18 |
import { useUserSelectionStore } from '@onboarding/state/UserSelections' |
| 19 |
import { Logo, Spinner } from '@onboarding/svg' |
| 20 |
|
| 21 |
export const CreatingSite = () => { |
| 22 |
const [isShowing] = useState(true) |
| 23 |
const [confettiReady, setConfettiReady] = useState(false) |
| 24 |
const [warnOnLeaveReady, setWarnOnLeaveReady] = useState(true) |
| 25 |
const canLaunch = useUserSelectionStore((state) => state.canLaunch()) |
| 26 |
const { siteType, siteInformation, pages, style, plugins } = |
| 27 |
useUserSelectionStore() |
| 28 |
const [info, setInfo] = useState([]) |
| 29 |
const [infoDesc, setInfoDesc] = useState([]) |
| 30 |
const inform = (msg) => setInfo((info) => [msg, ...info]) |
| 31 |
const informDesc = (msg) => setInfoDesc((infoDesc) => [msg, ...infoDesc]) |
| 32 |
const dryRun = useRef() |
| 33 |
useWarnOnLeave(warnOnLeaveReady) |
| 34 |
|
| 35 |
const doEverything = useCallback(async () => { |
| 36 |
if (!canLaunch) { |
| 37 |
throw new Error(__('Site is not ready to launch.', 'extendify')) |
| 38 |
} |
| 39 |
inform(__('Applying site styles', 'extendify')) |
| 40 |
informDesc(__('A beautiful site in... 3, 2, 1', 'extendify')) |
| 41 |
await runAtLeastFor( |
| 42 |
async () => await updateOption('blogname', siteInformation.title), |
| 43 |
2000, |
| 44 |
{ dryRun: dryRun.current }, |
| 45 |
) |
| 46 |
await runAtLeastFor( |
| 47 |
async () => await updateGlobalStyleVariant(style?.variation ?? {}), |
| 48 |
2000, |
| 49 |
{ dryRun: dryRun.current }, |
| 50 |
) |
| 51 |
await runAtLeastFor( |
| 52 |
async () => |
| 53 |
await updateTemplatePart( |
| 54 |
'extendable//header', |
| 55 |
style?.headerCode, |
| 56 |
), |
| 57 |
2000, |
| 58 |
{ dryRun: dryRun.current }, |
| 59 |
) |
| 60 |
await runAtLeastFor( |
| 61 |
async () => |
| 62 |
await updateTemplatePart( |
| 63 |
'extendable//footer', |
| 64 |
style?.footerCode, |
| 65 |
), |
| 66 |
2000, |
| 67 |
{ dryRun: dryRun.current }, |
| 68 |
) |
| 69 |
|
| 70 |
inform(__('Creating site pages', 'extendify')) |
| 71 |
informDesc(__('Starting off with a full site...', 'extendify')) |
| 72 |
let pageIds |
| 73 |
try { |
| 74 |
inform(__('Generating page content', 'extendify')) |
| 75 |
await runAtLeastFor( |
| 76 |
async () => { |
| 77 |
pageIds = await createWordpressPages(pages, siteType, style) |
| 78 |
const updatedHeaderCode = addLaunchPagesToNav( |
| 79 |
pages, |
| 80 |
pageIds, |
| 81 |
style?.headerCode, |
| 82 |
) |
| 83 |
await updateTemplatePart( |
| 84 |
'extendable//header', |
| 85 |
updatedHeaderCode, |
| 86 |
) |
| 87 |
}, |
| 88 |
2000, |
| 89 |
{ dryRun: dryRun.current }, |
| 90 |
) |
| 91 |
await new Promise((resolve) => setTimeout(resolve, 2000)) |
| 92 |
} catch (e) { |
| 93 |
/* do nothing */ |
| 94 |
} |
| 95 |
|
| 96 |
if (plugins?.length) { |
| 97 |
inform(__('Installing suggested plugins', 'extendify')) |
| 98 |
for (const [index, plugin] of plugins.entries()) { |
| 99 |
// TODO: instead of updating here, we could have a progress component |
| 100 |
// that we can update a % of the width every index/n |
| 101 |
informDesc( |
| 102 |
__( |
| 103 |
`${index + 1}/${plugins.length}: ${plugin.name}`, |
| 104 |
'extendify', |
| 105 |
), |
| 106 |
) |
| 107 |
try { |
| 108 |
await installPlugin(plugin) |
| 109 |
} catch (e) { |
| 110 |
/* do nothing */ |
| 111 |
} |
| 112 |
await new Promise((resolve) => setTimeout(resolve, 2000)) |
| 113 |
} |
| 114 |
} |
| 115 |
|
| 116 |
inform(__('Setting up your site assistant', 'extendify')) |
| 117 |
informDesc(__('Helping your site to be successful...', 'extendify')) |
| 118 |
await runAtLeastFor( |
| 119 |
async () => |
| 120 |
await trashWordpressPages([ |
| 121 |
{ slug: 'hello-world', type: 'post' }, |
| 122 |
{ slug: 'sample-page', type: 'page' }, |
| 123 |
]), |
| 124 |
2000, |
| 125 |
{ dryRun: dryRun.current }, |
| 126 |
) |
| 127 |
if (!dryRun.current) { |
| 128 |
await updateOption('permalink_structure', '/%postname%/') |
| 129 |
} |
| 130 |
inform(__('Your site has been created!', 'extendify')) |
| 131 |
informDesc(__('Redirecting in 3, 2, 1...', 'extendify')) |
| 132 |
// fire confetti here |
| 133 |
setConfettiReady(true) |
| 134 |
setWarnOnLeaveReady(false) |
| 135 |
await new Promise((resolve) => setTimeout(resolve, 2500)) |
| 136 |
|
| 137 |
return pageIds |
| 138 |
}, [pages, plugins, siteType, style, canLaunch, siteInformation.title]) |
| 139 |
|
| 140 |
useEffect(() => { |
| 141 |
const q = new URLSearchParams(window.location.search) |
| 142 |
dryRun.current = q.has('dry-run') |
| 143 |
}, []) |
| 144 |
|
| 145 |
useEffect(() => { |
| 146 |
doEverything().then(() => { |
| 147 |
window.location.replace( |
| 148 |
window.extOnbData.adminUrl + |
| 149 |
'admin.php?page=extendify-assist&extendify-launch-success', |
| 150 |
) |
| 151 |
}) |
| 152 |
}, [doEverything]) |
| 153 |
|
| 154 |
useConfetti( |
| 155 |
{ |
| 156 |
particleCount: 2, |
| 157 |
angle: 320, |
| 158 |
spread: 120, |
| 159 |
origin: { x: 0, y: 0 }, |
| 160 |
colors: ['var(--ext-partner-theme-primary-text, #ffffff)'], |
| 161 |
}, |
| 162 |
2500, |
| 163 |
confettiReady, |
| 164 |
) |
| 165 |
|
| 166 |
return ( |
| 167 |
<Transition |
| 168 |
show={isShowing} |
| 169 |
appear={true} |
| 170 |
enter="transition-all ease-in-out duration-500" |
| 171 |
enterFrom="md:w-40vw md:max-w-md" |
| 172 |
enterTo="md:w-full md:max-w-full" |
| 173 |
className="bg-partner-primary-bg text-partner-primary-text py-12 px-10 md:h-screen flex flex-col justify-between md:w-40vw md:max-w-md flex-shrink-0"> |
| 174 |
<div className="max-w-prose"> |
| 175 |
<div className="md:min-h-48"> |
| 176 |
{window.extOnbData?.partnerLogo && ( |
| 177 |
<div className="pb-8"> |
| 178 |
<img |
| 179 |
style={{ maxWidth: '200px' }} |
| 180 |
src={window.extOnbData.partnerLogo} |
| 181 |
alt={window.extOnbData?.partnerName ?? ''} |
| 182 |
/> |
| 183 |
</div> |
| 184 |
)} |
| 185 |
<div> |
| 186 |
{info.map((step, index) => { |
| 187 |
if (!index) { |
| 188 |
return ( |
| 189 |
<Transition |
| 190 |
appear={true} |
| 191 |
show={isShowing} |
| 192 |
enter="transition-opacity duration-1000" |
| 193 |
enterFrom="opacity-0" |
| 194 |
enterTo="opacity-100" |
| 195 |
leave="transition-opacity duration-1000" |
| 196 |
leaveFrom="opacity-100" |
| 197 |
leaveTo="opacity-0" |
| 198 |
className="text-4xl flex space-x-4 items-center" |
| 199 |
key={step}> |
| 200 |
{step} |
| 201 |
</Transition> |
| 202 |
) |
| 203 |
} |
| 204 |
})} |
| 205 |
<div className="flex space-x-4 items-center mt-6"> |
| 206 |
<Spinner className="animate-spin" /> |
| 207 |
{infoDesc.map((step, index) => { |
| 208 |
if (!index) { |
| 209 |
return ( |
| 210 |
<Transition |
| 211 |
appear={true} |
| 212 |
show={isShowing} |
| 213 |
enter="transition-opacity duration-1000" |
| 214 |
enterFrom="opacity-0" |
| 215 |
enterTo="opacity-100" |
| 216 |
leave="transition-opacity duration-1000" |
| 217 |
leaveFrom="opacity-100" |
| 218 |
leaveTo="opacity-0" |
| 219 |
className="text-lg" |
| 220 |
key={step}> |
| 221 |
{step} |
| 222 |
</Transition> |
| 223 |
) |
| 224 |
} |
| 225 |
})} |
| 226 |
</div> |
| 227 |
</div> |
| 228 |
</div> |
| 229 |
</div> |
| 230 |
<div className="hidden md:flex items-center space-x-3"> |
| 231 |
<span className="opacity-70 text-xs"> |
| 232 |
{__('Powered by', 'extendify')} |
| 233 |
</span> |
| 234 |
<span className="relative"> |
| 235 |
<Logo className="logo text-partner-primary-text w-28" /> |
| 236 |
<span className="absolute -bottom-2 right-3 font-semibold tracking-tight"> |
| 237 |
Launch |
| 238 |
</span> |
| 239 |
</span> |
| 240 |
</div> |
| 241 |
</Transition> |
| 242 |
) |
| 243 |
} |
| 244 |
|