diff --git a/dt-reports/magic-url-setup.php b/dt-reports/magic-url-setup.php index 95a8e1b4b..4049718c6 100644 --- a/dt-reports/magic-url-setup.php +++ b/dt-reports/magic-url-setup.php @@ -320,7 +320,7 @@ function app_link_qr(evt) { $('#modal-small').foundation('open') } function app_link_reset(evt) { - const { url, title, key } = get_app(evt.target); + const { url, title, key, sysType, recordId } = get_app(evt.target); const { ID: post_id, post_type, corresponds_to_user } = window.detailsSettings.post_fields; const modalTitle = document.getElementById('modal-small-title'); @@ -331,11 +331,14 @@ function app_link_reset(evt) { const button = modalContent.querySelector('.button'); const loadingSpinner = modalContent.querySelector('.loading-spinner'); + button.addEventListener('click', function () { this.disabled = true; loadingSpinner.classList.add('active'); try { + const sys_type = sysType || (corresponds_to_user ? 'wp_user' : 'post'); + const id = recordId || (corresponds_to_user || post_id); if (corresponds_to_user) { // to reset a user link, we'll just turn it off and back on again @@ -351,6 +354,10 @@ function app_link_reset(evt) { .done(function (data2) { if ('removed' !== data2) { app_link_set_url(evt.target, key, data2); + // Clear expiration data when link is reset + if (window.wpApiShare) { + clear_expiration_after_reset(key, id, sys_type); + } } }) $('#modal-small').foundation('close') @@ -358,12 +365,17 @@ function app_link_reset(evt) { } }) } else { + const newHash = window.sha256( Date.now() ); window.API.update_post( post_type, - post_id, {[key]: window.sha256( Date.now() )} + post_id, {[key]: newHash} ).done( newPost => { $('#modal-small').foundation('close') app_link_set_url(evt.target, key, newPost[key]); + // Clear expiration data when link is reset + if (window.wpApiShare) { + clear_expiration_after_reset(key, id, sys_type); + } }) } } catch (err) { @@ -372,6 +384,70 @@ function app_link_reset(evt) { }) } + function clear_expiration_after_reset(metaKey, id, sysType) { + if (!window.wpApiShare) return; + + const endpointUrl = window.wpApiShare.root + 'disciple_tools_magic_links/v1/clear_link_expiration'; + + const payload = { + meta_key: metaKey, + sys_type: sysType + }; + + // Add user_id or post_id based on sys_type + if (sysType === 'wp_user') { + payload.user_id = id; + } else { + payload.post_id = id; + } + + $.ajax({ + url: endpointUrl, + method: 'POST', + data: payload, + beforeSend: function(xhr) { + xhr.setRequestHeader('X-WP-Nonce', window.wpApiShare.nonce); + }, + success: function(data) { + if (data && data.success) { + // Clear expiration display on frontend + const expirationDisplay = document.getElementById('app-expiration-display-' + metaKey); + if (expirationDisplay) { + expirationDisplay.textContent = '---'; + } + + // Remove expiration badge and clear data attributes + const appAccordion = document.querySelector('.app-accordion.' + metaKey); + if (appAccordion) { + appAccordion.dataset.expiresTs = ''; + appAccordion.dataset.expiresFormatted = '---'; + appAccordion.dataset.expiresFormattedShort = ''; + const badge = appAccordion.querySelector('.app-expiration-badge'); + if (badge) { + badge.remove(); + } + + // Reset label text when expiration has been cleared + const resetButton = appAccordion.querySelector('.app-link-row .reset'); + if (resetButton) { + const resetRow = resetButton.closest('.app-link-row'); + const resetLabel = resetRow ? resetRow.querySelector('.app-link-label') : null; + if (resetLabel) { + resetLabel.textContent = ''; + } + } + } + } + }, + error: function(xhr, status, error) { + // Silently fail - not critical + if (console && console.warn) { + console.warn('Could not clear expiration:', error); + } + } + }); + } + function app_link_set_url(target, meta_key, value) { console.log({ meta_key, @@ -388,6 +464,125 @@ function app_link_set_url(target, meta_key, value) { const appCopy = appAccordion.querySelector('.app-copy'); appCopy.dataset.value = url; } + + function app_link_set_expiration(evt) { + const appAccordion = evt.target.closest('.app-accordion'); + const { key, sysType, recordId } = get_app(evt.target); + const { ID: post_id, corresponds_to_user } = window.detailsSettings.post_fields; + + const metaKey = key; + const expirationAmount = document.getElementById('app-expiration-amount-' + metaKey).value; + const expirationTimeUnit = document.getElementById('app-expiration-time-unit-' + metaKey).value; + + // Validate input (amount and unit required) + if (!expirationAmount || parseInt(expirationAmount, 10) <= 0 || !expirationTimeUnit) { + alert(''); + return; + } + + // Determine sys_type and id + const sys_type = sysType || (corresponds_to_user ? 'wp_user' : 'post'); + const id = recordId || (corresponds_to_user || post_id); + + // Build request payload + const payload = { + meta_key: metaKey, + sys_type: sys_type, + links_expire_within_amount: expirationAmount, + links_expire_within_time_unit: expirationTimeUnit + }; + + // Add id based on sys_type + if (sys_type === 'wp_user') { + payload.user_id = id; + } else { + payload.post_id = id; + } + + // Disable button and show loading + const button = evt.target; + const originalText = button.textContent; + button.disabled = true; + button.textContent = ''; + + // Build endpoint URL + const endpointUrl = window.wpApiShare.root + 'disciple_tools_magic_links/v1/set_link_expiration_direct'; + + // Make request + $.ajax({ + url: endpointUrl, + method: 'POST', + data: payload, + beforeSend: function(xhr) { + xhr.setRequestHeader('X-WP-Nonce', window.wpApiShare.nonce); + }, + success: function(data) { + if (data && data.success) { + // Update expiration display (full date inside accordion) + const expirationDisplay = document.getElementById('app-expiration-display-' + metaKey); + if (data.expires) { + const formatted = data.expires.ts_formatted || '---'; + if (expirationDisplay) { + expirationDisplay.textContent = formatted; + } + + // Update data attributes + appAccordion.dataset.expiresTs = data.expires.ts || ''; + appAccordion.dataset.expiresFormatted = data.expires.ts_formatted || '---'; + appAccordion.dataset.expiresFormattedShort = data.expires.ts_formatted_short || ''; + + // Update or create summary badge with short format (Exp: M/D/YY H:mm) + const shortFormatted = data.expires.ts_formatted_short || ''; + const badge = appAccordion.querySelector('.app-expiration-badge'); + if (shortFormatted) { + const badgeText = '' + shortFormatted; + if (badge) { + badge.textContent = badgeText; + } else { + const appLabel = appAccordion.querySelector('.app-label'); + if (appLabel) { + const newBadge = document.createElement('span'); + newBadge.className = 'app-expiration-badge'; + newBadge.style.cssText = 'font-size: 0.85em; color: #666; margin-top: 0.25rem;'; + newBadge.textContent = badgeText; + // Insert under the title (after first child) + const insertBefore = appLabel.children[1] || null; + appLabel.insertBefore(newBadge, insertBefore); + } + } + } else if (badge) { + badge.remove(); + } + + // Update reset label to mention clearing expiration + const resetButton = appAccordion.querySelector('.app-link-row .reset'); + if (resetButton) { + const resetRow = resetButton.closest('.app-link-row'); + const resetLabel = resetRow ? resetRow.querySelector('.app-link-label') : null; + if (resetLabel) { + resetLabel.textContent = ''; + } + } + } + + // Show success message + if (window.toastr) { + window.toastr.success(''); + } + } else { + alert(data.message || ''); + } + }, + error: function(xhr, status, error) { + console.error('Error updating expiration:', error, xhr.responseJSON); + alert(''); + }, + complete: function() { + button.disabled = false; + button.textContent = originalText; + } + }); + } '', + 'ts_formatted' => '---', + 'ts_base' => '' + ]; + $post_id = isset( $post['ID'] ) ? $post['ID'] : get_the_ID(); + $sys_type = $user_id ? 'wp_user' : 'post'; + $record_id = $user_id ? $user_id : $post_id; + + // Determine if the active magic link plugin version supports expiration helpers + $magic_link_expiration_supported = ( + class_exists( 'Disciple_Tools_Bulk_Magic_Link_Sender_API' ) + && method_exists( 'Disciple_Tools_Bulk_Magic_Link_Sender_API', 'capture_expiry_details' ) + ); + + if ( $magic_link_expiration_supported ) { + // Try to find matching link_obj for backward compatibility + $matching_link_obj = null; + + static $cached_link_objs = null; + if ( is_null( $cached_link_objs ) ) { + $cached_link_objs = Disciple_Tools_Bulk_Magic_Link_Sender_API::fetch_option_link_objs(); + } + $link_objs = $cached_link_objs; + + foreach ( $link_objs as $link_obj ) { + $generated_key = Disciple_Tools_Bulk_Magic_Link_Sender_API::generate_magic_link_type_key( $link_obj ); + if ( $generated_key === $meta_key ) { + $matching_link_obj = $link_obj; + break; + } + } + + // Fetch expiration using unified wrapper (checks meta first, then link_obj) + $expiration_data = Disciple_Tools_Bulk_Magic_Link_Sender_API::capture_expiry_details( + $meta_key, + $record_id, + $sys_type, + $matching_link_obj + ); + } + + // Prepare short expiration format using site date/time settings + $date_time_format = get_option( 'date_format' ) . ' ' . get_option( 'time_format' ); + $exp_ts = $expiration_data['ts'] ?? ''; + $exp_short = ! empty( $exp_ts ) ? date_i18n( $date_time_format, (int) $exp_ts ) : ''; ?>
-
- -
- - -
- +
+ + + + + + + +
+ + +
+
+ + +