PluginProbe
Extendify / 0.10.2
Extendify v0.10.2
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 / components / ExitModal.js

ExitModal.js in Extendify 0.10.2, at src/Onboarding/components/ExitModal.js

198 lines 7.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { Button } from '@wordpress/components'
2 import { useRef, useState, useEffect } from '@wordpress/element'
3 import { __ } from '@wordpress/i18n'
4 import { Icon, close } from '@wordpress/icons'
5 import { Dialog } from '@headlessui/react'
6 import classNames from 'classnames'
7 import { getExitQuestions } from '@onboarding/api/DataApi'
8 import { updateOption } from '@onboarding/api/WPApi'
9 import { useGlobalStore } from '@onboarding/state/Global'
10 import { useUserSelectionStore } from '@onboarding/state/UserSelections'
11 import { Checkmark } from '@onboarding/svg'
12
13 export const ExitModal = () => {
14 const { exitModalOpen, closeExitModal, hoveredOverExitButton } =
15 useGlobalStore()
16 const { setExitFeedback } = useUserSelectionStore()
17 const [value, setValue] = useState()
18 const [options, setOptions] = useState([])
19 const initialFocus = useRef()
20 const closeLaunch = async () => {
21 // Store when Launch is skipped.
22 await updateOption(
23 'extendify_onboarding_skipped',
24 new Date().toISOString(),
25 )
26 location.href = window.extOnbData.adminUrl
27 }
28
29 useEffect(() => {
30 if (!hoveredOverExitButton) return
31 // Intentionally not using SWR so we only try once.
32 getExitQuestions()
33 .then(({ data }) => {
34 if (!Array.isArray(data) || !data[0]?.key) {
35 throw new Error('Invalid data')
36 }
37 setOptions(data)
38 })
39 .catch(() =>
40 setOptions([
41 {
42 key: 'I still want it, just disabling temporary',
43 label: __(
44 'I still want it, just disabling temporary',
45 'extendify',
46 ),
47 },
48 {
49 key: "I don't really need it",
50 label: __("I don't really need it", 'extendify'),
51 },
52 {
53 key: 'I plan on using my own theme or builder',
54 label: __(
55 'I plan on using my own theme or builder',
56 'extendify',
57 ),
58 },
59 {
60 key: "The theme designs don't look great",
61 label: __(
62 "The theme designs don't look great",
63 'extendify',
64 ),
65 },
66 { key: 'Other', label: __('Other', 'extendify') },
67 ]),
68 )
69 .finally(() => {
70 initialFocus.current?.focus()
71 })
72 }, [hoveredOverExitButton])
73
74 useEffect(() => {
75 setExitFeedback(value)
76 }, [value, setExitFeedback])
77
78 return (
79 <Dialog
80 as="div"
81 className="extendify-onboarding"
82 open={exitModalOpen}
83 initialFocus={initialFocus}
84 onClose={closeExitModal}>
85 <div className="absolute top-0 mx-auto w-full h-full overflow-hidden p-2 md:p-6 md:flex justify-center items-center z-max">
86 <div
87 className="fixed inset-0 bg-black bg-opacity-40 transition-opacity"
88 aria-hidden="true"
89 />
90 <Dialog.Title className="sr-only">
91 {__('Exit Launch')}
92 </Dialog.Title>
93 <form
94 onSubmit={closeLaunch}
95 style={{ maxWidth: '400px' }}
96 className="sm:flex relative shadow-2xl sm:overflow-hidden mx-auto bg-white flex flex-col p-8">
97 <Button
98 className="absolute top-0 right-0"
99 onClick={closeExitModal}
100 icon={<Icon icon={close} size={24} />}
101 label={__('Exit Launch', 'extendify')}
102 />
103 <p className="m-0 text-lg font-bold text-left">
104 {__(
105 'Thanks for trying Extendify Launch. How can we make this better?',
106 'extendify',
107 )}
108 </p>
109 <div
110 role="radiogroup"
111 className="flex flex-col text-base mt-4">
112 {options.map(({ key, label }, i) => (
113 <LabeledCheckbox
114 initialFocus={i ? undefined : initialFocus}
115 key={key}
116 slug={key}
117 label={label}
118 value={value}
119 setValue={(v) => setValue(v)}
120 />
121 ))}
122 </div>
123 <div className="flex justify-end mt-8">
124 {/* If they've made a choice, we are sending it in real time */}
125 {value ? null : (
126 <button
127 className="px-4 py-3 mr-4 button-focus"
128 type="button"
129 onClick={closeLaunch}>
130 {__('Skip', 'extendify')}
131 </button>
132 )}
133 <button
134 className="px-4 py-3 font-bold bg-partner-primary-bg text-partner-primary-text button-focus"
135 type="button"
136 onClick={closeLaunch}>
137 {__('Submit', 'extendify')}
138 </button>
139 </div>
140 </form>
141 </div>
142 </Dialog>
143 )
144 }
145
146 const LabeledCheckbox = ({ label, slug, setValue, value, initialFocus }) => {
147 const { setExitFeedback } = useUserSelectionStore()
148 const needsInput = slug === 'Other'
149 const checked = value === slug
150 const id = slug
151 .toLowerCase()
152 .replace(/ /g, '-')
153 .replace(/[^\w-]+/g, '')
154
155 return (
156 <>
157 <span className="flex items-center leading-loose">
158 <span
159 onClick={() => setValue(slug)}
160 onKeyDown={(e) => {
161 if (e.key === 'Enter' || e.key === ' ') {
162 setValue(slug)
163 }
164 }}
165 role="radio"
166 aria-labelledby={id}
167 aria-checked={checked}
168 data-value={slug}
169 // Will focus on the first element in the list
170 ref={initialFocus}
171 tabIndex={0}
172 className="w-5 h-5 relative mr-2">
173 <span className="h-5 w-5 rounded-sm m-0 block border border-gray-900 button-focus" />
174 <Checkmark
175 className={classNames('absolute -top-0.5 -left-0.5', {
176 'text-partner-primary-bg': checked,
177 })}
178 style={{ width: 24, color: '#fff' }}
179 role="presentation"
180 />
181 </span>
182 <span onClick={() => setValue(slug)} id={id}>
183 {label}
184 </span>
185 </span>
186 {needsInput && checked ? (
187 <textarea
188 onChange={(e) =>
189 setExitFeedback(`Other: ${e.target.value}`)
190 }
191 className="border border-gray-400 mt-2 text-base p-2"
192 rows="4"
193 />
194 ) : null}
195 </>
196 )
197 }
198