Components
9 months ago
autoloader.js
1 year ago
edit.js
6 months ago
ic-arrow-up-right-square.svg
11 months ago
index.js
6 months ago
reach-logo.svg
11 months ago
styles.scss
1 month ago
view.js
1 month ago
edit.js
278 lines
| 1 | import {useState, useEffect} from "react"; |
| 2 | import apiFetch from '@wordpress/api-fetch'; |
| 3 | import {useSelect, select} from '@wordpress/data'; |
| 4 | |
| 5 | import ServerSideRender from "@wordpress/server-side-render"; |
| 6 | import {useBlockProps, InspectorControls} from "@wordpress/block-editor"; |
| 7 | import { |
| 8 | PanelBody, |
| 9 | SelectControl, |
| 10 | TextControl, |
| 11 | ToggleControl, |
| 12 | CheckboxControl, Flex, FlexItem, Button, |
| 13 | } from "@wordpress/components"; |
| 14 | import {__} from '@wordpress/i18n'; |
| 15 | import Connect from "./Components/Connect"; |
| 16 | import Dialog from "./Components/Dialog"; |
| 17 | |
| 18 | const Edit = ({attributes, setAttributes, clientId}) => { |
| 19 | const {isPostPublished, postPermalink} = useSelect((select) => ({ |
| 20 | isPostPublished: select('core/editor').isCurrentPostPublished() |
| 21 | })); |
| 22 | const [newTagName, setNewTagName] = useState(''); |
| 23 | const blockProps = useBlockProps(); |
| 24 | const nonce = wp.data.select('core/editor').getEditorSettings().nonce || ''; |
| 25 | const [isConnected, setIsConnected] = useState(true); |
| 26 | const [showAddNewTag, setShowAddNewTag] = useState(false); |
| 27 | const [isLoading, setIsLoading] = useState(false); |
| 28 | const [tags, setTags] = useState([]); |
| 29 | const [showDialog, setShowDialog] = useState(false); |
| 30 | const [lastStatus, setLastStatus] = useState(null); |
| 31 | |
| 32 | const layoutOptions = [ |
| 33 | {label: __('Default', 'hostinger-reach'), value: 'default'}, |
| 34 | {label: __('Inline', 'hostinger-reach'), value: 'inline'} |
| 35 | ]; |
| 36 | |
| 37 | useEffect(() => { |
| 38 | if (isPostPublished && lastStatus !== null && lastStatus !== 'publish') { |
| 39 | setShowDialog(true); |
| 40 | } |
| 41 | }, [isPostPublished, lastStatus]); |
| 42 | |
| 43 | |
| 44 | useEffect(() => { |
| 45 | setLastPostStatus(); |
| 46 | fetchTags(); |
| 47 | checkConnection(); |
| 48 | }, []); |
| 49 | |
| 50 | |
| 51 | useEffect(() => { |
| 52 | if (attributes.formId) return; |
| 53 | setAttributes({formId: clientId}); |
| 54 | }, [setAttributes]); |
| 55 | |
| 56 | const fetchTags = async () => { |
| 57 | await getTags(); |
| 58 | }; |
| 59 | |
| 60 | |
| 61 | const checkConnection = async () => { |
| 62 | try { |
| 63 | const response = await apiFetch({ |
| 64 | path: '/hostinger-reach/v1/overview', |
| 65 | method: 'GET', |
| 66 | headers: { |
| 67 | 'X-WP-Nonce': nonce, |
| 68 | }, |
| 69 | parse: false, |
| 70 | }); |
| 71 | |
| 72 | if (response.ok) { |
| 73 | setIsConnected(true); |
| 74 | } else { |
| 75 | setIsConnected(false); |
| 76 | } |
| 77 | |
| 78 | } catch (err) { |
| 79 | setIsConnected(false); |
| 80 | } |
| 81 | } |
| 82 | |
| 83 | const setLastPostStatus = () => { |
| 84 | const lastKnownStatus = select('core/editor').getEditedPostAttribute('status'); |
| 85 | setLastStatus(lastKnownStatus); |
| 86 | } |
| 87 | |
| 88 | const getTags = async () => { |
| 89 | try { |
| 90 | const response = await apiFetch({ |
| 91 | path: '/hostinger-reach/v1/tags', |
| 92 | method: 'GET', |
| 93 | headers: { |
| 94 | 'X-WP-Nonce': nonce, |
| 95 | }, |
| 96 | parse: false, |
| 97 | }); |
| 98 | |
| 99 | if (response.ok) { |
| 100 | const responseData = await response.json(); |
| 101 | const tagNames = responseData.data.map(tag => tag.value); |
| 102 | setTags(tagNames); |
| 103 | } |
| 104 | } catch (err) { |
| 105 | console.error(err); |
| 106 | } |
| 107 | } |
| 108 | |
| 109 | const createTag = async ( tag ) => { |
| 110 | try { |
| 111 | setIsLoading(true); |
| 112 | const response = await apiFetch({ |
| 113 | path: '/hostinger-reach/v1/tags', |
| 114 | method: 'POST', |
| 115 | headers: { |
| 116 | 'X-WP-Nonce': nonce, |
| 117 | }, |
| 118 | data: { |
| 119 | names: [tag] |
| 120 | }, |
| 121 | }); |
| 122 | |
| 123 | if (response && response.data) { |
| 124 | const tagNames = response.data.map(tag => tag.value); |
| 125 | setTags([...tagNames, ...tags]); |
| 126 | } |
| 127 | } catch ( err ) { |
| 128 | console.error(err); |
| 129 | } finally { |
| 130 | setIsLoading(false); |
| 131 | } |
| 132 | } |
| 133 | |
| 134 | const isTagSelected = (tagName) => { |
| 135 | const selectedTags = attributes.tags || []; |
| 136 | return selectedTags.includes(tagName); |
| 137 | } |
| 138 | |
| 139 | const handleTagToggle = (tagName) => { |
| 140 | const selectedTags = attributes.tags || []; |
| 141 | let newTags; |
| 142 | if (isTagSelected(tagName)) { |
| 143 | newTags = selectedTags.filter(tag => tag !== tagName); |
| 144 | } else { |
| 145 | newTags = [...selectedTags, tagName]; |
| 146 | } |
| 147 | |
| 148 | setAttributes({tags: newTags}); |
| 149 | }; |
| 150 | |
| 151 | const addTag = async () => { |
| 152 | const newTag = newTagName.trim(); |
| 153 | |
| 154 | if (!newTag) { |
| 155 | return; |
| 156 | } |
| 157 | |
| 158 | const tagExists = tags.some(tag => tag === newTag); |
| 159 | |
| 160 | if (!tagExists) { |
| 161 | await createTag( newTag ); |
| 162 | } |
| 163 | |
| 164 | if (!isTagSelected(newTag)) { |
| 165 | handleTagToggle(newTag); |
| 166 | } |
| 167 | |
| 168 | setNewTagName(''); |
| 169 | } |
| 170 | |
| 171 | const handleKeyPress = (event) => { |
| 172 | if (event.key === 'Enter') { |
| 173 | event.preventDefault(); |
| 174 | addTag(); |
| 175 | } |
| 176 | }; |
| 177 | |
| 178 | const toggleAddNewTag = () => { |
| 179 | setShowAddNewTag( ! showAddNewTag ); |
| 180 | } |
| 181 | |
| 182 | return <div {...blockProps}> |
| 183 | <InspectorControls key="hostinger-reach-block-controls"> |
| 184 | <PanelBody title={__("Settings", "hostinger-reach")}> |
| 185 | {!isConnected && <Connect/>} |
| 186 | <TextControl |
| 187 | disabled |
| 188 | label={__('Form ID', 'hostinger-reach')} |
| 189 | value={attributes.formId} |
| 190 | help={__('Unique identifier for this form', 'hostinger-reach')} |
| 191 | /> |
| 192 | <div> |
| 193 | <strong>{__('Tags', 'hostinger-reach')}</strong> |
| 194 | {tags.length > 0 && ( |
| 195 | <div className="hostinger-reach-block-tags"> |
| 196 | {tags.map((tag) => { |
| 197 | const selectedTags = attributes.tags || []; |
| 198 | return ( |
| 199 | <CheckboxControl |
| 200 | key={tag} |
| 201 | label={tag} |
| 202 | checked={selectedTags.includes(tag)} |
| 203 | onChange={() => handleTagToggle(tag)} |
| 204 | /> |
| 205 | ); |
| 206 | })} |
| 207 | </div> |
| 208 | )} |
| 209 | </div> |
| 210 | <Button |
| 211 | className="hostinger-reach-block-toggler" |
| 212 | variant="link" |
| 213 | onClick={toggleAddNewTag} |
| 214 | > |
| 215 | {__('Add New Tag', 'hostinger-reach')} |
| 216 | </Button> |
| 217 | {showAddNewTag && <Flex className="hostinger-reach-block-newtag" direction="column" align="flex-start" gap={1}> |
| 218 | <FlexItem style={{flex: 1}}> |
| 219 | <TextControl |
| 220 | label={__('New Tag Name', 'hostinger-reach')} |
| 221 | value={newTagName} |
| 222 | onChange={(value) => { |
| 223 | setNewTagName(value); |
| 224 | }} |
| 225 | onKeyDown={handleKeyPress} |
| 226 | help={__('Enter tag name and press Enter or click Add Tag', 'hostinger-reach')} |
| 227 | /> |
| 228 | </FlexItem> |
| 229 | <FlexItem> |
| 230 | <Button |
| 231 | variant="secondary" |
| 232 | onClick={addTag} |
| 233 | disabled={!newTagName.trim() || isLoading} |
| 234 | > |
| 235 | {__('Add Tag', 'hostinger-reach')} |
| 236 | </Button> |
| 237 | </FlexItem> |
| 238 | </Flex> } |
| 239 | <ToggleControl |
| 240 | label={__("Show Name Field?", "hostinger-reach")} |
| 241 | key="hostinger-reach-block-show-name-field" |
| 242 | checked={attributes.showName} |
| 243 | onChange={(value) => |
| 244 | setAttributes({showName: value}) |
| 245 | } |
| 246 | /> |
| 247 | <ToggleControl |
| 248 | label={__("Show Surname Field?", "hostinger-reach")} |
| 249 | key="hostinger-reach-block-show-surname-field" |
| 250 | checked={attributes.showSurname} |
| 251 | onChange={(value) => |
| 252 | setAttributes({showSurname: value}) |
| 253 | } |
| 254 | /> |
| 255 | </PanelBody> |
| 256 | <PanelBody title={__('Layout Settings', 'hostinger-reach')}> |
| 257 | <SelectControl |
| 258 | label={__('Layout', 'hostinger-reach')} |
| 259 | value={attributes.layout} |
| 260 | options={layoutOptions} |
| 261 | onChange={(value) => setAttributes({layout: value})} |
| 262 | /> |
| 263 | </PanelBody> |
| 264 | |
| 265 | </InspectorControls> |
| 266 | {!isConnected && <Connect/>} |
| 267 | <ServerSideRender |
| 268 | key="hostinger-reach-server-side-renderer" |
| 269 | block="hostinger-reach/subscription" |
| 270 | attributes={attributes} |
| 271 | /> |
| 272 | {showDialog && <Dialog onClose={() => setShowDialog(false)}/>} |
| 273 | </div> |
| 274 | |
| 275 | } |
| 276 | |
| 277 | export default Edit; |
| 278 |