PluginProbe
Extendify / 0.11.0
Extendify v0.11.0
3.2.1 3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 0.6.0 All 127 releases
extendify / src / Onboarding / pages / SiteTypeSelect.js

SiteTypeSelect.js in Extendify 0.11.0, at src/Onboarding/pages/SiteTypeSelect.js

208 lines 8.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { useEffect, useState, useRef } from '@wordpress/element'
2 import { __ } from '@wordpress/i18n'
3 import { mutate } from 'swr'
4 import { getSiteTypes } from '@onboarding/api/DataApi'
5 import { updateOption } from '@onboarding/api/WPApi'
6 import { useFetch } from '@onboarding/hooks/useFetch'
7 import { PageLayout } from '@onboarding/layouts/PageLayout'
8 import { usePagesStore } from '@onboarding/state/Pages'
9 import { useUserSelectionStore } from '@onboarding/state/UserSelections'
10 import { pageState } from '@onboarding/state/factory'
11 import { SearchIcon, LeftArrowIcon } from '@onboarding/svg'
12 import {
13 fetcher as styleFetcher,
14 fetchData as styleFetchData,
15 } from './SiteStyle'
16
17 export const fetcher = () => getSiteTypes()
18 export const fetchData = () => ({ key: 'site-types' })
19 export const state = pageState('Site Industry', (set, get) => ({
20 title: __('Site Industry', 'extendify'),
21 default: undefined,
22 showInSidebar: true,
23 ready: false,
24 isDefault: () =>
25 useUserSelectionStore.getState()?.siteType?.slug ===
26 get().default?.slug,
27 }))
28 export const SiteTypeSelect = () => {
29 const { nextPage } = usePagesStore()
30 const siteType = useUserSelectionStore((state) => state.siteType)
31 const feedback = useUserSelectionStore(
32 (state) => state.feedbackMissingSiteType,
33 )
34 const [search, setSearch] = useState('')
35 const searchRef = useRef(null)
36 const { data: siteTypes, loading } = useFetch(fetchData, fetcher)
37 const visibleSiteTypes = siteTypes?.filter((option) => {
38 const { title } = option
39 const searchTerm = search?.toLowerCase()
40 if (!searchTerm) return option?.featured
41 if (title.toLowerCase().indexOf(searchTerm) > -1) return true
42 })
43
44 const showMissingInput = () =>
45 window.extOnbData?.activeTests?.['remove-dont-see-inputs'] === 'A'
46
47 useEffect(() => {
48 state.setState({ ready: !loading })
49 }, [loading])
50
51 useEffect(() => {
52 const raf = requestAnimationFrame(() => searchRef.current?.focus())
53 return () => cancelAnimationFrame(raf)
54 }, [searchRef])
55
56 useEffect(() => {
57 if (loading) return
58 if (siteType?.slug) return
59 const defaultSiteType = siteTypes?.find(
60 (record) => record.slug === 'default',
61 )
62 if (defaultSiteType) {
63 const defaultS = {
64 label: defaultSiteType.title,
65 recordId: defaultSiteType.id,
66 slug: defaultSiteType.slug,
67 }
68 useUserSelectionStore.getState().setSiteType(defaultS)
69 state.setState({ default: defaultS })
70 }
71 }, [loading, siteType?.slug, siteTypes])
72
73 useEffect(() => {
74 if (!search) return
75 const timer = setTimeout(() => {
76 useUserSelectionStore.setState({
77 siteTypeSearch: [
78 ...useUserSelectionStore.getState().siteTypeSearch,
79 search,
80 ],
81 })
82 }, 500)
83 return () => clearTimeout(timer)
84 }, [search])
85
86 const selectSiteType = async (optionValue) => {
87 useUserSelectionStore.getState().setSiteType({
88 label: optionValue.title,
89 recordId: optionValue.id,
90 slug: optionValue.slug,
91 styles: optionValue.styles,
92 })
93 await updateOption('extendify_siteType', optionValue)
94 nextPage()
95 }
96
97 return (
98 <PageLayout>
99 <div>
100 <h1 className="text-3xl text-partner-primary-text mb-4 mt-0">
101 {__('Welcome to your WordPress site', 'extendify')}
102 </h1>
103 <p className="text-base opacity-70 mb-0">
104 {__(
105 'Design and launch your site with this guided experience, or head right into the WordPress dashboard if you know your way around.',
106 'extendify',
107 )}
108 </p>
109 </div>
110 <div className="w-full relative max-w-onboarding-sm mx-auto">
111 <div className="sticky bg-white top-10 z-40 pt-9 pb-3 mb-2">
112 <div className="mb-4">
113 <h2 className="text-lg m-0 text-gray-900">
114 {__('What is your site about?', 'extendify')}
115 </h2>
116 </div>
117 <div className="mx-auto search-panel flex items-center justify-center relative mb-6">
118 <input
119 ref={searchRef}
120 type="text"
121 className="w-full bg-gray-100 h-12 pl-4 input-focus rounded-none ring-offset-0 focus:bg-white"
122 value={search}
123 onChange={(e) => setSearch(e.target.value)}
124 placeholder={__('Search...', 'extendify')}
125 />
126 <SearchIcon className="icon-search" />
127 </div>
128 {loading && <p>{__('Loading...', 'extendify')}</p>}
129 </div>
130 {visibleSiteTypes?.length > 0 && (
131 <div className="relative">
132 {visibleSiteTypes.map((option) => (
133 <SelectButton
134 key={option.id}
135 selectSiteType={selectSiteType}
136 option={option}
137 />
138 ))}
139 </div>
140 )}
141 {!loading && visibleSiteTypes?.length === 0 && (
142 <div className="mx-auto w-full">
143 <div className="uppercase">
144 {__('No Results', 'extendify')}
145 </div>
146 {showMissingInput() && (
147 <>
148 <h2 className="text-lg mt-12 mb-4 text-gray-900">
149 {__(
150 "Don't see what you're looking for?",
151 'extendify',
152 )}
153 </h2>
154 <div className="search-panel flex items-center justify-center relative">
155 <input
156 type="text"
157 className="w-full bg-gray-100 h-12 pl-4 input-focus rounded-none ring-offset-0 focus:bg-white"
158 value={feedback}
159 onChange={(e) =>
160 useUserSelectionStore
161 .getState()
162 .setFeedbackMissingSiteType(
163 e.target.value,
164 )
165 }
166 placeholder={__(
167 'Describe your site...',
168 'extendify',
169 )}
170 />
171 </div>
172 </>
173 )}
174 </div>
175 )}
176 </div>
177 </PageLayout>
178 )
179 }
180
181 const SelectButton = ({ option, selectSiteType }) => {
182 const hoveringTimeout = useRef(0)
183 return (
184 <button
185 onClick={() => {
186 selectSiteType(option)
187 }}
188 onMouseEnter={() => {
189 // Prefetch style templates when hovering over site type
190 window.clearTimeout(hoveringTimeout.current)
191 hoveringTimeout.current = window.setTimeout(() => {
192 const data = () => styleFetchData(option)
193 mutate(data, (cache) => {
194 if (cache?.length) return cache
195 return styleFetcher(data())
196 })
197 }, 100)
198 }}
199 onMouseLeave={() => {
200 window.clearTimeout(hoveringTimeout.current)
201 }}
202 className="flex border border-gray-800 hover:text-partner-primary-bg focus:text-partner-primary-bg items-center justify-between mb-3 p-4 py-3 relative w-full button-focus bg-transparent">
203 <span className="text-left">{option.title}</span>
204 <LeftArrowIcon />
205 </button>
206 )
207 }
208