GuideSteps.js (12714B)
1 import { 2 useEffect, useState, render, unmountComponentAtNode, 3 } from '@wordpress/element' 4 import { __ } from '@wordpress/i18n' 5 import { useGlobalStore } from '../../state/GlobalState' 6 import { useUserStore } from '../../state/User' 7 import { General as GeneralApi } from '../../api/General' 8 import { useTaxonomyStore } from '../../state/Taxonomies' 9 import classNames from 'classnames' 10 import { useTemplatesStore } from '../../state/Templates' 11 import SearchPredict from '../../components/SearchPredict' 12 import { Transition } from '@headlessui/react' 13 import WaitingCrunching from '../modals/WaitingCrunchingModal' 14 import { Templates as TemplatesApi } from '../../api/Templates' 15 16 export default function GuideSteps() { 17 const updateSearchParams = useTemplatesStore(state => state.updateSearchParams) 18 const templates = useTemplatesStore(state => state.templates) 19 const taxonomyDefaultState = useTemplatesStore(state => state.taxonomyDefaultState) 20 const setActiveTemplate = useTemplatesStore(state => state.setActive) 21 const appendTemplates = useTemplatesStore(state => state.appendTemplates) 22 const updateTaxonomies = useTemplatesStore(state => state.updateTaxonomies) 23 const taxonomies = useTaxonomyStore(state => state.taxonomies) 24 const preferred = useUserStore(state => state.preferredOptions) 25 const [allCats, setAllCats] = useState([]) 26 const [stepOneTouched, setStepOneTouched] = useState(false) 27 const [stepTwoTouched, setStepTwoTouched] = useState(false) 28 const [stepThreeTouched, setStepThreeTouched] = useState(false) 29 30 const setPreferred = (key, value) => { 31 useUserStore.getState().updatePreferredOption(key, value) 32 } 33 const typeTax = preferred?.type == 'template' 34 ? 'tax_page_types' 35 : 'tax_pattern_types' 36 37 const closeGuide = () => { 38 GeneralApi.ping('guide-cancelled') 39 templates.length && useTemplatesStore.setState({ skipNextFetch: true }) 40 useGlobalStore.setState({ currentPage: 'main' }) 41 } 42 const fetchDelayThenDisplay = () => { 43 updateSearchParams({ 44 taxonomies: Object.assign( 45 {}, taxonomyDefaultState, preferred.taxonomies, 46 ), 47 type: preferred.type, 48 search: preferred.search, 49 }) 50 const action = new Promise((resolve) => { 51 useTemplatesStore.setState({ skipNextFetch: true }) 52 const setupTemplates = (data) => { 53 appendTemplates(data) 54 data.length === 1 && setActiveTemplate(data[0]) 55 useTemplatesStore.setState({ 56 nextPage: data.offset, 57 }) 58 } 59 // TODO: this could probably be smarter and recursive we want to remove more 60 TemplatesApi.get(useTemplatesStore.getState().searchParams).then((response) => { 61 if (response.records.length) { 62 setupTemplates(response.records) 63 return resolve() 64 } 65 // Remove the style and try again 66 updateTaxonomies({ tax_style: '' }) 67 TemplatesApi.get(useTemplatesStore.getState().searchParams).then((response) => { 68 setupTemplates(response.records) 69 return resolve() 70 }) 71 }) 72 }) 73 const callback = async () => { 74 await new Promise((resolve) => setTimeout(resolve, 1500)) 75 useGlobalStore.setState({ 76 currentPage: 'main', 77 }) 78 unmountComponentAtNode(document.getElementById('extendify-util')) 79 } 80 render(<WaitingCrunching 81 action={action} 82 callback={callback} 83 text={__('Finding templates...', 'extendify-sdk')} 84 />, document.getElementById('extendify-util')) 85 } 86 87 const showStepTwo = () => (stepOneTouched || preferred?.taxonomies?.tax_categories) ? true : false 88 const showStepThree = () => (showStepTwo() && (!taxonomies[typeTax] || stepTwoTouched || preferred?.taxonomies[typeTax])) ? true : false 89 const showFinalButton = () => (showStepThree() && (stepThreeTouched || preferred?.taxonomies?.tax_style)) ? true : false 90 91 useEffect(() => { 92 if (!taxonomies?.tax_categories) { 93 return 94 } 95 96 const all = Object.values(taxonomies.tax_categories) 97 // Map over all terms 98 .map((term) => 99 // Filter out terms not of this type (pattern/template) 100 term.children.filter(c => c.type.includes(preferred?.type)).map(c => c.term)) 101 // merge all together 102 .flat().sort() 103 104 setAllCats([...new Set(all)]) 105 }, [taxonomies, preferred?.type]) 106 107 const emptyToolbar = <div className="w-full h-16 relative z-10 border-solid border-0 flex-shrink-0"> 108 <div className="flex justify-between items-center px-6 sm:px-12 h-full"> 109 <div className="flex space-x-12 h-full"> 110 </div> 111 <div className="space-x-2 transform sm:translate-x-8"> 112 <button 113 type="button" 114 className="components-button has-icon" 115 onClick={closeGuide}> 116 <svg width="24" height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" size="24" role="img" aria-hidden="true" focusable="false"><path d="M13 11.8l6.1-6.3-1-1-6.1 6.2-6.1-6.2-1 1 6.1 6.3-6.5 6.7 1 1 6.5-6.6 6.5 6.6 1-1z"></path></svg> 117 <span className="sr-only">{__('Close library', 'extendify-sdk')}</span> 118 </button> 119 </div> 120 </div> 121 </div> 122 123 return <div className="w-full h-full flex flex-col items-center relative shadow-xl max-w-screen-4xl mx-auto bg-white"> 124 {emptyToolbar} 125 <section className="flex-grow w-full justify-between flex flex-col overflow-y-scroll"> 126 <div className="flex flex-col w-full h-full p-8 pb-0 md:p-16 md:pb-0 2xl:p-28 2xl:pb-0 max-w-screen-2xl mx-auto"> 127 <h1 className="text-left m-0 mb-12 text-7xl"> 128 {__('Hello', 'extendify-sdk')} 129 </h1> 130 <div className="flex-grow lg:flex justify-between space-y-8 lg:space-y-0 lg:space-x-16 xl:space-x-32"> 131 <div className="text-left flex-shrink-0 lg:w-1/2"> 132 <h2 className="text-2xl m-0 mb-8"> 133 {preferred?.type === 'template' ? 134 __('Help me find a template', 'extendify-sdk') : 135 __('Help me find a pattern', 'extendify-sdk')} 136 </h2> 137 <div className="flex flex-col space-y-8"> 138 <div> 139 <p className="text-base text-gray-900 m-0 mb-5">{__('Select your industry:', 'extendify-sdk')}</p> 140 <SearchPredict 141 list={allCats} 142 value={preferred?.taxonomies?.tax_categories} 143 touched={() => setStepOneTouched(true)} 144 label={__('Category', 'extendify-sdk')} 145 setValue={(v) => setPreferred('tax_categories', v)}/> 146 </div> 147 148 <Transition 149 enter="transform transition duration-50 duration-300" 150 enterFrom="opacity-0 translate-y-2" 151 enterTo="opacity-100 translate-y-0" 152 show={showStepTwo()}> 153 {taxonomies[typeTax] && <div onChange={() => setStepTwoTouched(true)}> 154 <label 155 className="text-base text-gray-900 m-0 mb-4 block" 156 htmlFor="typeTax-search"> 157 {__('What type of section are you trying to add?', 'extendify-sdk')} 158 </label> 159 <select 160 onChange={(event) => setPreferred(typeTax, event.target.value)} 161 value={preferred?.taxonomies[typeTax] ?? ''} 162 id="typeTax-search" 163 className="h-8 max-w-md min-h-0 w-full px-2 text-sm border border-gray-900 button-focus-big-green rounded-none"> 164 <option value="">{__('Select type', 'extendify-sdk')}</option> 165 {Object.values(taxonomies[typeTax]).map((t) => { 166 return <option key={t.term} value={t.term}> 167 {t.term} 168 </option> 169 })} 170 </select> 171 </div>} 172 </Transition> 173 </div> 174 </div> 175 <div className="mt-16 text-left"> 176 <Transition 177 enter="transform transition duration-50 duration-300" 178 enterFrom="opacity-0 translate-y-2" 179 enterTo="opacity-100 translate-y-0" 180 show={showStepThree()}> 181 <div onClick={() => setStepThreeTouched(true)}> 182 <p className="text-base text-gray-900 m-0 mb-4"> 183 {__('What style best matches what you\'re looking for?', 'extendify-sdk')} 184 </p> 185 <div> 186 {taxonomies?.tax_style && <div className="grid grid-cols-2 gap-4 mb-8"> 187 {Object.values(taxonomies.tax_style) 188 .filter((t) => t?.type?.includes(preferred?.type) && t?.thumbnail) 189 .map((t) => { 190 return <button 191 key={t.term} 192 onClick={() => setPreferred('tax_style', t.term)} 193 className={classNames({ 194 'bg-transparent p-0 m-0 cursor-pointer': true, 195 'ring-4 ring-offset-4 ring-extendify-main outline-none': t.term === preferred?.taxonomies?.tax_style, 196 })}> 197 <span className="sr-only">{t.term}</span> 198 <img className="w-full" src={t.thumbnail} alt={`Style named ${t.term}`} /> 199 </button> 200 })} 201 </div>} 202 </div> 203 </div> 204 </Transition> 205 <Transition 206 enter="transform transition duration-50 duration-300" 207 enterFrom="opacity-0 translate-y-2" 208 enterTo="opacity-100 translate-y-0" 209 show={showFinalButton()}> 210 <button 211 onClick={() => fetchDelayThenDisplay()} 212 className="button-extendify-main button-focus-big-green p-4 text-xl"> 213 {preferred?.type === 'template' ? 214 __('View templates', 'extendify-sdk') : 215 __('View patterns', 'extendify-sdk')} 216 </button> 217 </Transition> 218 </div> 219 </div> 220 </div> 221 <footer className="flex justify-between p-14 w-full"> 222 <div> 223 <svg className="block" width="64" height="64" viewBox="0 0 103 103" fill="none" xmlns="http://www.w3.org/2000/svg"> 224 <rect y="25.75" width="70.8125" height="77.25" fill="#000000"/> 225 <rect x="45.0625" width="57.9375" height="57.9375" fill="#37C2A2"/> 226 </svg> 227 </div> 228 </footer> 229 </section> 230 </div> 231 }