index.tsx
295 lines
| 1 | import {FormProvider, SubmitHandler, useForm} from 'react-hook-form'; |
| 2 | import {__} from '@wordpress/i18n'; |
| 3 | import styles from './Form.module.scss'; |
| 4 | import FormModal from '../../FormModal'; |
| 5 | import {MergeCampaignFormInputs, MergeCampaignFormProps} from './types'; |
| 6 | import {useState} from 'react'; |
| 7 | import apiFetch from '@wordpress/api-fetch'; |
| 8 | import {addQueryArgs} from '@wordpress/url'; |
| 9 | import {getGiveCampaignsListTableWindowData} from '../../CampaignsListTable'; |
| 10 | |
| 11 | /** |
| 12 | * Campaign Form Modal component |
| 13 | * |
| 14 | * @since 4.0.0 |
| 15 | */ |
| 16 | export default function MergeCampaignsForm({isOpen, handleClose, title, campaigns}: MergeCampaignFormProps) { |
| 17 | const [step, setStep] = useState<number>(1); |
| 18 | |
| 19 | const methods = useForm<MergeCampaignFormInputs>({ |
| 20 | defaultValues: { |
| 21 | destinationCampaignId: '', |
| 22 | }, |
| 23 | }); |
| 24 | |
| 25 | const { |
| 26 | register, |
| 27 | handleSubmit, |
| 28 | formState: {isDirty, isSubmitting}, |
| 29 | watch, |
| 30 | } = methods; |
| 31 | |
| 32 | const destinationCampaignId = watch('destinationCampaignId'); |
| 33 | |
| 34 | const requiredAsterisk = <span className={`givewp-field-required ${styles.fieldRequired}`}>*</span>; |
| 35 | |
| 36 | const onSubmit: SubmitHandler<MergeCampaignFormInputs> = async (inputs, event) => { |
| 37 | event.preventDefault(); |
| 38 | |
| 39 | if (step !== 2) { |
| 40 | return; |
| 41 | } |
| 42 | |
| 43 | const campaignsToMergeIds = campaigns.selected.filter((id) => id != inputs.destinationCampaignId); |
| 44 | |
| 45 | try { |
| 46 | const response = await apiFetch({ |
| 47 | path: addQueryArgs('/givewp/v3/campaigns/' + destinationCampaignId + '/merge', { |
| 48 | campaignsToMergeIds: campaignsToMergeIds, |
| 49 | }), |
| 50 | method: 'PATCH', |
| 51 | }); |
| 52 | |
| 53 | console.log('Merge campaigns response: ', response); |
| 54 | |
| 55 | // Go to success page |
| 56 | setStep(3); |
| 57 | |
| 58 | //Reset bulk actions selector |
| 59 | const selects = document.querySelectorAll('#give-admin-campaigns-root select'); |
| 60 | selects.forEach((select) => { |
| 61 | const selectElement = select as HTMLSelectElement; |
| 62 | selectElement.selectedIndex = 0; |
| 63 | }); |
| 64 | |
| 65 | // Uncheck all checkboxes |
| 66 | const checkboxes = document.querySelectorAll(".giveListTable input[type='checkbox']"); |
| 67 | checkboxes.forEach((checkbox) => { |
| 68 | const input = checkbox as HTMLInputElement; |
| 69 | input.checked = false; |
| 70 | }); |
| 71 | // @ts-ignore |
| 72 | document.querySelector('.giveListTable #giveListTableSelectAll').checked = false; |
| 73 | |
| 74 | //Remove campaignsToMergeIds from the list table. |
| 75 | const adminFormsListViewItems = document.querySelectorAll('tr'); |
| 76 | if (adminFormsListViewItems.length > 0) { |
| 77 | adminFormsListViewItems.forEach((itemElement) => { |
| 78 | const select = itemElement.querySelector('.giveListTableSelect'); |
| 79 | |
| 80 | if (!select) { |
| 81 | return; |
| 82 | } |
| 83 | |
| 84 | const campaignId = select.getAttribute('data-id'); |
| 85 | if (campaignsToMergeIds.includes(campaignId)) { |
| 86 | itemElement.remove(); |
| 87 | } |
| 88 | }); |
| 89 | } |
| 90 | //handleClose(response); |
| 91 | } catch (error) { |
| 92 | // Go to error page |
| 93 | setStep(4); |
| 94 | console.error('Error merging campaigns: ', error); |
| 95 | } |
| 96 | }; |
| 97 | |
| 98 | const extractTextFromLink = (link) => { |
| 99 | const parser = new DOMParser(); |
| 100 | const doc = parser.parseFromString(link, 'text/html'); |
| 101 | return doc.querySelector('a')?.textContent || link; |
| 102 | }; |
| 103 | |
| 104 | return ( |
| 105 | <FormProvider {...methods}> |
| 106 | <FormModal |
| 107 | isOpen={isOpen} |
| 108 | handleClose={handleClose} |
| 109 | title={title} |
| 110 | handleSubmit={handleSubmit(onSubmit)} |
| 111 | errors={[]} |
| 112 | className={styles.campaignForm} |
| 113 | > |
| 114 | {step === 1 && ( |
| 115 | <> |
| 116 | <div className="givewp-campaigns__form-row"> |
| 117 | <p className={styles.intro}> |
| 118 | {__( |
| 119 | 'All selected campaigns will be merged into the destination campaign. This means that forms, donors, donations, and all related data will be added to the destination campaign, and the merged campaigns will cease to exist.', |
| 120 | 'give' |
| 121 | )} |
| 122 | </p> |
| 123 | </div> |
| 124 | <button |
| 125 | type="submit" |
| 126 | onClick={() => setStep(2)} |
| 127 | className={`button button-primary ${styles.button}`} |
| 128 | aria-disabled={false} |
| 129 | disabled={false} |
| 130 | > |
| 131 | {__('Proceed', 'give')} |
| 132 | </button> |
| 133 | </> |
| 134 | )} |
| 135 | {step === 2 && ( |
| 136 | <> |
| 137 | <div className="givewp-campaigns__form-row"> |
| 138 | <label htmlFor="title"> |
| 139 | {__('Select your destination campaign', 'give')} {requiredAsterisk} |
| 140 | </label> |
| 141 | <span>{__('All selected campaigns will be merged into this campaign.', 'give')}</span> |
| 142 | <select {...register('destinationCampaignId', {valueAsNumber: true})} defaultValue=""> |
| 143 | <option value="" disabled hidden> |
| 144 | {__('Choose from selected campaigns', 'give')} |
| 145 | </option> |
| 146 | {campaigns.selected.map((id, index) => ( |
| 147 | <option key={id} value={id}> |
| 148 | {extractTextFromLink(campaigns.names[index])} |
| 149 | </option> |
| 150 | ))} |
| 151 | </select> |
| 152 | </div> |
| 153 | <button |
| 154 | type="submit" |
| 155 | className={`button button-primary ${styles.button} ${isSubmitting ? 'disabled' : ''}`} |
| 156 | aria-disabled={!isDirty} |
| 157 | disabled={!isDirty} |
| 158 | > |
| 159 | {isSubmitting ? __('Merging in progress...', 'give') : __('Merge', 'give')} |
| 160 | </button> |
| 161 | {isDirty && ( |
| 162 | <div className={styles.notice}> |
| 163 | <svg |
| 164 | width="20" |
| 165 | height="20" |
| 166 | viewBox="0 0 20 20" |
| 167 | fill="none" |
| 168 | xmlns="http://www.w3.org/2000/svg" |
| 169 | > |
| 170 | <path |
| 171 | fillRule="evenodd" |
| 172 | clipRule="evenodd" |
| 173 | d="M10 .836a9.167 9.167 0 1 0 0 18.333A9.167 9.167 0 0 0 10 .836zm0 5a.833.833 0 1 0 0 1.667h.009a.833.833 0 0 0 0-1.667h-.008zm.834 4.167a.833.833 0 0 0-1.667 0v3.333a.833.833 0 1 0 1.667 0v-3.333z" |
| 174 | fill="#0C7FF2" |
| 175 | /> |
| 176 | </svg> |
| 177 | |
| 178 | <p>{__('Once completed, this action is irreversible.', 'give')}</p> |
| 179 | </div> |
| 180 | )} |
| 181 | </> |
| 182 | )} |
| 183 | {step === 3 && ( |
| 184 | <> |
| 185 | <div className="givewp-campaigns__form-row"> |
| 186 | <div className={styles.returnMessage}> |
| 187 | <svg |
| 188 | width="40" |
| 189 | height="40" |
| 190 | viewBox="0 0 40 40" |
| 191 | fill="none" |
| 192 | xmlns="http://www.w3.org/2000/svg" |
| 193 | > |
| 194 | <path |
| 195 | fillRule="evenodd" |
| 196 | clipRule="evenodd" |
| 197 | d="M20 1.664c-10.126 0-18.334 8.208-18.334 18.333 0 10.126 8.208 18.334 18.333 18.334 10.126 0 18.334-8.208 18.334-18.334 0-10.125-8.208-18.333-18.334-18.333zm8.678 14.512a1.667 1.667 0 0 0-2.357-2.357l-8.822 8.821-3.821-3.821a1.667 1.667 0 0 0-2.357 2.357l5 5c.65.65 1.706.65 2.357 0l10-10z" |
| 198 | fill="#459948" |
| 199 | /> |
| 200 | </svg> |
| 201 | |
| 202 | <label htmlFor="title">{__('Campaigns have been successfully merged', 'give')}</label> |
| 203 | <span> |
| 204 | {__( |
| 205 | 'All donations, donors, and forms from selected campaigns now belong to your destination campaign.', |
| 206 | 'give' |
| 207 | )} |
| 208 | </span> |
| 209 | </div> |
| 210 | </div> |
| 211 | <div |
| 212 | className="givewp-campaigns__form-row givewp-campaigns__form-row--half" |
| 213 | style={{marginBottom: 0}} |
| 214 | > |
| 215 | <button |
| 216 | type="submit" |
| 217 | onClick={() => handleClose()} |
| 218 | className={`button button-secondary ${styles.button} ${styles.previousButton}`} |
| 219 | > |
| 220 | {__('Back to campaign list', 'give')} |
| 221 | </button> |
| 222 | |
| 223 | <button |
| 224 | type="submit" |
| 225 | onClick={() => |
| 226 | (window.location.href = |
| 227 | getGiveCampaignsListTableWindowData().adminUrl + |
| 228 | 'edit.php?post_type=give_forms&page=give-campaigns&id=' + |
| 229 | destinationCampaignId) |
| 230 | } |
| 231 | className={`button button-primary ${styles.button}`} |
| 232 | aria-disabled={false} |
| 233 | disabled={false} |
| 234 | > |
| 235 | {__('View destination campaign', 'give')} |
| 236 | </button> |
| 237 | </div> |
| 238 | </> |
| 239 | )} |
| 240 | {step === 4 && ( |
| 241 | <> |
| 242 | <div className="givewp-campaigns__form-row"> |
| 243 | <div className={styles.returnMessage}> |
| 244 | <svg |
| 245 | width="40" |
| 246 | height="40" |
| 247 | viewBox="0 0 40 40" |
| 248 | fill="none" |
| 249 | xmlns="http://www.w3.org/2000/svg" |
| 250 | > |
| 251 | <path |
| 252 | fillRule="evenodd" |
| 253 | clipRule="evenodd" |
| 254 | d="M20 1.668c-10.125 0-18.333 8.208-18.333 18.333 0 10.125 8.208 18.334 18.333 18.334 10.125 0 18.333-8.209 18.333-18.334S30.125 1.668 20 1.668zm1.667 11.667a1.667 1.667 0 0 0-3.334 0V20a1.667 1.667 0 1 0 3.334 0v-6.666zM20 25a1.667 1.667 0 1 0 0 3.334h.017a1.667 1.667 0 0 0 0-3.334H20z" |
| 255 | fill="#D92D0B" |
| 256 | /> |
| 257 | </svg> |
| 258 | <label htmlFor="title">{__("Campaigns couldn't be merged", 'give')}</label> |
| 259 | <span> |
| 260 | {__( |
| 261 | 'An error occurred during the merging process. Please try again, or contact our support team if the issue persists.', |
| 262 | 'give' |
| 263 | )} |
| 264 | </span> |
| 265 | </div> |
| 266 | </div> |
| 267 | <div |
| 268 | className="givewp-campaigns__form-row givewp-campaigns__form-row--half" |
| 269 | style={{marginBottom: 0}} |
| 270 | > |
| 271 | <button |
| 272 | type="submit" |
| 273 | onClick={() => handleClose()} |
| 274 | className={`button button-secondary ${styles.button} ${styles.previousButton}`} |
| 275 | > |
| 276 | {__('Back to campaign list', 'give')} |
| 277 | </button> |
| 278 | |
| 279 | <button |
| 280 | type="submit" |
| 281 | onClick={() => setStep(2)} |
| 282 | className={`button button-primary ${styles.button}`} |
| 283 | aria-disabled={false} |
| 284 | disabled={false} |
| 285 | > |
| 286 | {__('Try again', 'give')} |
| 287 | </button> |
| 288 | </div> |
| 289 | </> |
| 290 | )} |
| 291 | </FormModal> |
| 292 | </FormProvider> |
| 293 | ); |
| 294 | } |
| 295 |