PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.8.13
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.8.13
1.8.13.1 1.8.13 1.8.12.3 1.8.12.2 1.8.12.1 1.8.12 1.8.11.3 1.8.11.2 1.8.11.1 1.8.11 1.6.6 1.6.60 1.6.7 1.6.8 1.6.9 1.7.0 1.7.0.1 1.7.0.11 1.7.0.12 1.7.0.14 1.7.0.2 1.7.0.3 1.7.0.5 1.7.0.6 1.7.0.7 All 212 releases
charitable / assets / js / integrations / square / square-settings.js

square-settings.js in Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) 1.8.13, at assets/js/integrations/square/square-settings.js

405 lines 11.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /* global charitable_admin, CharitableAdmin, wpf */
2
3 /**
4 * Charitable Square settings function.
5 *
6 * @since 1.8.7
7 */
8 const CharitableSettingsSquare = window.CharitableSettingsSquare || ( function( document, window, $ ) {
9 /**
10 * Elements.
11 *
12 * @since 1.8.7
13 *
14 * @type {Object}
15 */
16 let $el = {};
17
18 const iconSpinner = '<i class="fa fa-spinner fa-spin" aria-hidden="true"></i>';
19
20 /**
21 * Public functions and properties.
22 *
23 * @since 1.8.7
24 *
25 * @type {Object}
26 */
27 const app = {
28
29 /**
30 * Start the engine.
31 *
32 * @since 1.8.7
33 */
34 init() {
35 $( app.ready );
36 },
37
38 /**
39 * Document ready.
40 *
41 * @since 1.8.7
42 */
43 ready() {
44 // Wait for DOM to be fully loaded
45 $(document).ready(function() {
46 // Initialize all element references after DOM is loaded
47 $el = {
48 sandboxModeCheckbox: $( '#charitable-setting-square-sandbox-mode' ),
49 sandboxConnectionStatusBlock: $( '#charitable-setting-row-square-connection-status-sandbox' ),
50 productionConnectionStatusBlock: $( '#charitable-setting-row-square-connection-status-production' ),
51 sandboxLocationBlock: $( '#charitable-setting-row-square-location-id-sandbox' ),
52 sandboxLocationStatusBlock: $( '#charitable-setting-row-square-location-status-sandbox' ),
53 productionLocationBlock: $( '#charitable-setting-row-square-location-id-production' ),
54 productionLocationStatusBlock: $( '#charitable-setting-row-square-location-status-production' ),
55 refreshBtn: $( '.charitable-square-refresh-btn' ),
56 copyButton: $( '#charitable-setting-row-square-webhooks-endpoint-set .charitable-copy-to-clipboard' ),
57 webhookEndpointUrl: $( 'input#charitable-square-webhook-endpoint-url' ),
58 webhookMethod: $( 'input[name="square-webhooks-communication"]' ),
59 webhookCommunicationStatusNotice: $( '#charitable-setting-row-square-webhooks-communication-status' ),
60 webhookConnectBtn: $( '#charitable-setting-square-webhooks-connect, .charitable-btn-connect-webhooks' ),
61 };
62
63 // Bind events after elements are initialized
64 app.events();
65 });
66 },
67
68 /**
69 * Register JS events.
70 *
71 * @since 1.8.7
72 */
73 events() {
74
75 // if ($el.webhookConnectBtn.length === 0) {
76 // console.error('Webhook connect button not found in DOM!');
77 // return;
78 // }
79
80 // Disabled webhook connect button functionality - now using manual webhook setup
81 // $el.webhookConnectBtn.on('click', app.modals.displayWebhookConfigPopup);
82 $el.sandboxModeCheckbox.on('change', app.credentialsFieldsDisplay);
83 $el.refreshBtn.on('click', app.refreshTokensCallback);
84 $el.webhookMethod.on('change', app.updateWebhookEndpointUrl);
85
86 // Add copy functionality for the new webhook URL field
87 $(document).on('click', '.charitable-copy-icon', function(e) {
88 e.preventDefault();
89 const targetId = $(this).data('clipboard-target');
90 const targetElement = $(targetId);
91 const $copyIcon = $(this);
92
93 if (targetElement.length) {
94 // Copy to clipboard using modern clipboard API
95 const textToCopy = targetElement.val();
96
97 if (navigator.clipboard && window.isSecureContext) {
98 // Use modern clipboard API
99 navigator.clipboard.writeText(textToCopy).then(function() {
100 // Show "Copied" state
101 $copyIcon.addClass('copied');
102
103 // Reset after 2 seconds
104 setTimeout(function() {
105 $copyIcon.removeClass('copied');
106 }, 2000);
107 }).catch(function(err) {
108 console.error('Failed to copy: ', err);
109 // Fallback to older method
110 fallbackCopyTextToClipboard(textToCopy, $copyIcon);
111 });
112 } else {
113 // Fallback for older browsers
114 fallbackCopyTextToClipboard(textToCopy, $copyIcon);
115 }
116 }
117 });
118
119 // Fallback copy function for older browsers
120 function fallbackCopyTextToClipboard(text, $copyIcon) {
121 const textArea = document.createElement('textarea');
122 textArea.value = text;
123
124 // Avoid scrolling to bottom
125 textArea.style.top = '0';
126 textArea.style.left = '0';
127 textArea.style.position = 'fixed';
128 textArea.style.opacity = '0';
129
130 document.body.appendChild(textArea);
131 textArea.focus();
132 textArea.select();
133
134 try {
135 const successful = document.execCommand('copy');
136 if (successful) {
137 // Show "Copied" state
138 $copyIcon.addClass('copied');
139
140 // Reset after 2 seconds
141 setTimeout(function() {
142 $copyIcon.removeClass('copied');
143 }, 2000);
144 }
145 } catch (err) {
146 console.error('Fallback: Oops, unable to copy', err);
147 }
148
149 document.body.removeChild(textArea);
150 }
151 },
152
153 /**
154 * Update the endpoint URL.
155 *
156 * @since 1.8.7
157 */
158 updateWebhookEndpointUrl() {
159 const checked = $el.webhookMethod.filter( ':checked' ).val(),
160 newUrl = charitable_admin.square.webhook_urls[ checked ];
161
162 $el.webhookEndpointUrl.val( newUrl );
163 $el.webhookCommunicationStatusNotice.removeClass( 'charitable-hide' );
164 },
165
166 /**
167 * Refresh tokens.
168 *
169 * @since 1.8.7
170 */
171 refreshTokensCallback() {
172 const $btn = $( this );
173 const buttonWidth = $btn.outerWidth();
174 const buttonLabel = $btn.text();
175 const settings = {
176 url: charitable_admin.ajax_url,
177 type: 'post',
178 dataType: 'json',
179 data: {
180 action: 'charitable_square_refresh_connection',
181 nonce: charitable_admin.nonce,
182 mode: $btn.data( 'mode' ),
183 },
184 beforeSend() {
185 $btn.css( 'width', buttonWidth ).html( iconSpinner ).prop( 'disabled', true );
186 },
187 };
188
189 let errorMessage = charitable_admin.square.refresh_error;
190
191 // Perform an Ajax request.
192 $.ajax( settings )
193 .done( function( response ) {
194 if ( response.success ) {
195 $btn
196 .css( 'pointerEvents', 'none' )
197 .removeClass( 'charitable-btn-light-grey' )
198 .addClass( 'charitable-btn-grey' )
199 .html( 'Refreshed!' );
200
201 $btn.closest( 'form' ).css( 'cursor', 'wait' );
202
203 window.location = $btn.data( 'url' );
204
205 return;
206 }
207
208 if (
209 Object.prototype.hasOwnProperty.call( response, 'data' ) &&
210 response.data !== ''
211 ) {
212 errorMessage = response.data;
213 }
214
215 $btn
216 .css( 'width', 'auto' )
217 .html( buttonLabel )
218 .prop( 'disabled', false );
219 app.modals.refreshTokensError( errorMessage );
220 } )
221 .fail( function() {
222 $btn
223 .css( 'width', 'auto' )
224 .html( buttonLabel )
225 .prop( 'disabled', false );
226 app.modals.refreshTokensError( errorMessage );
227 } );
228 },
229
230 /**
231 * Conditionally show Square mode switch warning.
232 *
233 * @since 1.8.7
234 */
235 credentialsFieldsDisplay() {
236 const sandboxModeEnabled = $el.sandboxModeCheckbox.is( ':checked' );
237
238 if ( sandboxModeEnabled ) {
239 $el.sandboxConnectionStatusBlock.show();
240 $el.sandboxLocationBlock.show();
241 $el.sandboxLocationStatusBlock.show();
242
243 $el.productionConnectionStatusBlock.hide();
244 $el.productionLocationBlock.hide();
245 $el.productionLocationStatusBlock.hide();
246 } else {
247 $el.sandboxConnectionStatusBlock.hide();
248 $el.sandboxLocationBlock.hide();
249 $el.sandboxLocationStatusBlock.hide();
250
251 $el.productionConnectionStatusBlock.show();
252 $el.productionLocationBlock.show();
253 $el.productionLocationStatusBlock.show();
254 }
255
256 if ( sandboxModeEnabled && $el.sandboxConnectionStatusBlock.find( '.charitable-square-connected' ).length ) {
257 return;
258 }
259
260 if ( ! sandboxModeEnabled && $el.productionConnectionStatusBlock.find( '.charitable-square-connected' ).length ) {
261 return;
262 }
263
264 app.modals.modeChangedWarning();
265 },
266
267 /**
268 * Modals.
269 *
270 * @since 1.8.7
271 */
272 modals: {
273
274 /**
275 * Show the warning modal when Square mode is changed.
276 *
277 * @since 1.8.7
278 */
279 modeChangedWarning() {
280 $.alert( {
281 title: charitable_admin.heads_up,
282 content: charitable_admin.square.mode_update,
283 icon: 'fa fa-exclamation-circle',
284 type: 'orange',
285 buttons: {
286 confirm: {
287 text: charitable_admin.ok,
288 btnClass: 'btn-confirm',
289 keys: [ 'enter' ],
290 },
291 },
292 } );
293 },
294
295 /**
296 * Refresh tokens error handling.
297 *
298 * @since 1.8.7
299 *
300 * @param {string} error Error message.
301 */
302 refreshTokensError( error ) {
303 $.alert( {
304 title: false,
305 content: error,
306 icon: 'fa fa-exclamation-circle',
307 type: 'orange',
308 buttons: {
309 confirm: {
310 text: charitable_admin.ok,
311 btnClass: 'btn-confirm',
312 keys: [ 'enter' ],
313 },
314 },
315 } );
316 },
317
318 /**
319 * Show popup with the ability to register a new webhook route or retrieve existing one.
320 *
321 * @since 1.8.7
322 */
323 // eslint-disable-next-line max-lines-per-function
324 displayWebhookConfigPopup() {
325 $.confirm( {
326 title: charitable_admin.square.webhook_create_title,
327 content: charitable_admin.square.webhook_create_description +
328 '<input type="text" id="charitable-square-personal-access-token" placeholder="' + charitable_admin.square.webhook_token_placeholder + '" value="">' +
329 '<p class="charitable-square-webhooks-connect-error error" style="display:none;">' + charitable_admin.square.token_is_required + '</p>',
330 icon: 'fa fa-info-circle',
331 type: 'blue',
332 buttons: {
333 confirm: {
334 text: charitable_admin.ok,
335 btnClass: 'btn-confirm',
336 keys: [ 'enter' ],
337 action() {
338 const modal = this;
339 const tokenField = modal.$content.find( '#charitable-square-personal-access-token' );
340 const errorMsg = modal.$content.find( '.error' );
341 const token = tokenField.val().trim();
342 const title = modal.$title;
343
344 // Disable the button to prevent multiple clicks.
345 $el.webhookConnectBtn.addClass( 'inactive' );
346
347 // Reset error message before validation
348 errorMsg.hide().text( '' );
349
350 if ( token === '' ) {
351 errorMsg.text( charitable_admin.square.token_is_required ).show();
352 return false; // Prevent modal from closing.
353 }
354
355 // Show loading indicator.
356 modal.buttons.confirm.setText( charitable_admin.loading );
357 modal.buttons.confirm.disable();
358
359 // Call API.
360 // app.createWebhook( token )
361 // .then( ( response ) => {
362 // modal.setContent( '<p>' + response.data.message + '</p>' );
363 // // Hide OK button and rename Cancel to Close.
364 // modal.buttons.confirm.hide();
365 // title.text( '' ).hide();
366 // modal.buttons.cancel.setText( charitable_admin.close );
367
368 // // Ensure user can manually close the modal.
369 // modal.buttons.cancel.action = function() {
370 // window.location.reload();
371 // };
372 // } )
373 // .catch( ( responseError ) => {
374 // errorMsg.text( responseError.data.message ).show();
375
376 // // Re-enable confirm button for retrying.
377 // modal.buttons.confirm.setText( charitable_admin.ok );
378 // modal.buttons.confirm.enable();
379 // } );
380
381 return false; // Prevent modal from closing immediately.
382 },
383 },
384 cancel: {
385 text: charitable_admin.cancel,
386 action() {
387 // Re-enable the button.
388 $el.webhookConnectBtn.removeClass( 'inactive' );
389
390 this.close();
391 },
392 },
393 },
394 } );
395 },
396 },
397 };
398
399 // Provide access to public functions/properties.
400 return app;
401 }( document, window, jQuery ) );
402
403 // Initialize.
404 CharitableSettingsSquare.init();
405