diff --git a/assets/css/settings-page.css b/assets/css/settings-page.css index 70d431ed6..44ed96d48 100644 --- a/assets/css/settings-page.css +++ b/assets/css/settings-page.css @@ -348,3 +348,69 @@ } } } + +.prpl-api-status-wrapper { + display: flex; + flex-direction: column; + gap: 1rem; + + .prpl-api-status-controls { + display: flex; + align-items: center; + gap: 0.5rem; + } + + .prpl-api-status-response-wrapper { + display: flex; + align-items: center; + gap: 0.5rem; + + svg { + width: 1rem; + height: 1rem; + } + + .prpl-api-status-icon-ok, + .prpl-api-status-icon-error, + .prpl-api-status-icon-spinner, + .prpl-api-status-text { + display: none; + } + + &.prpl-api-status-checking { + + .prpl-api-status-icon-spinner { + display: inline-block; + } + } + + &.prpl-api-status-ok { + + .prpl-api-status-icon-spinner { + display: none; + } + + .prpl-api-status-icon-ok, + .prpl-api-status-text { + display: inline-block; + } + } + + &.prpl-api-status-error { + + .prpl-api-status-icon-spinner { + display: none; + } + + .prpl-api-status-icon-error, + .prpl-api-status-text { + display: inline-block; + } + } + } + + input { + width: 20rem; + max-width: calc(100% - 2rem); + } +} diff --git a/assets/images/icon_server.svg b/assets/images/icon_server.svg new file mode 100644 index 000000000..332eb1c9c --- /dev/null +++ b/assets/images/icon_server.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/js/ajax-request.js b/assets/js/ajax-request.js index c7c510949..56e3a9a94 100644 --- a/assets/js/ajax-request.js +++ b/assets/js/ajax-request.js @@ -14,12 +14,14 @@ const progressPlannerAjaxRequest = ( { url, data } ) => { http.open( 'POST', url, true ); http.onreadystatechange = () => { let response; + try { response = JSON.parse( http.response ); } catch ( e ) { if ( http.readyState === 4 && http.status !== 200 ) { console.warn( http, e ); - return http.response; + // Reject the promise with the response. + reject( response ); } } diff --git a/assets/js/settings-page.js b/assets/js/settings-page.js index d7a813486..69edc3eb3 100644 --- a/assets/js/settings-page.js +++ b/assets/js/settings-page.js @@ -1,10 +1,10 @@ -/* global alert, prplDocumentReady */ +/* global alert, prplDocumentReady, progressPlannerSettingsPage, progressPlannerAjaxRequest, prplL10n */ /* * Settings Page * * A script to handle the settings page. * - * Dependencies: progress-planner/document-ready, wp-util + * Dependencies: progress-planner/document-ready, wp-util, progress-planner/ajax-request, progress-planner/l10n */ const prplTogglePageSelectorSettingVisibility = function ( page, value ) { const itemRadiosWrapperEl = document.querySelector( @@ -92,3 +92,108 @@ prplDocumentReady( function () { .getElementById( 'prpl-settings' ) .addEventListener( 'submit', prplFormSubmit ); } ); + +/** + * API Status Manager + * Handles the display and state of the API status check + */ +class APIStatusManager { + /** + * @param {string} wrapperSelector - The selector for the status wrapper element + */ + constructor( wrapperSelector ) { + this.wrapper = document.querySelector( wrapperSelector ); + } + + /** + * Update the status text content + * @param {string} text - The text to display + */ + updateStatusText( text ) { + const textElement = this.wrapper?.querySelector( + '.prpl-api-status-text' + ); + if ( textElement ) { + textElement.textContent = text; + } + } + + /** + * Update the status classes + * @param {string} status - The status class to add ('ok', 'error', 'checking') + */ + updateStatusClasses( status ) { + if ( ! this.wrapper ) { + return; + } + + this.wrapper.classList.remove( + 'prpl-api-status-ok', + 'prpl-api-status-error', + 'prpl-api-status-checking' + ); + this.wrapper.classList.add( `prpl-api-status-${ status }` ); + } + + /** + * Handle API response + * @param {Object} response - The API response + */ + handleResponse( response ) { + if ( response.status === 'ok' && response.nonce ) { + this.updateStatusText( prplL10n( 'remoteAPIStatusOk' ) ); + this.updateStatusClasses( 'ok' ); + } else { + this.updateStatusText( + response?.message || prplL10n( 'remoteAPIStatusError' ) + ); + this.updateStatusClasses( 'error' ); + } + } + + /** + * Handle API error + * @param {Error} error - The error object + */ + handleError( error ) { + this.updateStatusText( + error?.message || prplL10n( 'remoteAPIStatusError' ) + ); + this.updateStatusClasses( 'error' ); + } + + /** + * Check the API status + */ + checkStatus() { + if ( ! this.wrapper ) { + return; + } + + this.updateStatusClasses( 'checking' ); + + progressPlannerAjaxRequest( { + url: progressPlannerSettingsPage.onboardNonceURL, + data: { + site: progressPlannerSettingsPage.siteUrl, + }, + } ) + .then( ( response ) => this.handleResponse( response ) ) + .catch( ( error ) => this.handleError( error ) ); + } +} + +// Add click handler for API status check button +prplDocumentReady( () => { + // Initialize the API status manager + const apiStatusManager = new APIStatusManager( + '.prpl-api-status-response-wrapper' + ); + + const statusButton = document.getElementById( 'prpl-setting-api-status' ); + if ( statusButton ) { + statusButton.addEventListener( 'click', () => + apiStatusManager.checkStatus() + ); + } +} ); diff --git a/classes/admin/class-enqueue.php b/classes/admin/class-enqueue.php index 9b48aeff1..c27912bfa 100644 --- a/classes/admin/class-enqueue.php +++ b/classes/admin/class-enqueue.php @@ -388,6 +388,8 @@ public function get_localized_strings() { 'video' => \esc_html__( 'Video', 'progress-planner' ), 'watchVideo' => \esc_html__( 'Watch video', 'progress-planner' ), 'disabledRRCheckboxTooltip' => \esc_html__( 'Don\'t worry! This task will be checked off automatically when you\'ve completed it.', 'progress-planner' ), + 'remoteAPIStatusOk' => \esc_html__( 'API is accessible', 'progress-planner' ), + 'remoteAPIStatusError' => \esc_html__( 'API is not accessible', 'progress-planner' ), 'opensInNewWindow' => \esc_html__( 'Opens in new window', 'progress-planner' ), 'whyIsThisImportant' => \esc_html__( 'Why is this important?', 'progress-planner' ), /* translators: %s: The plugin name. */ diff --git a/classes/admin/class-page.php b/classes/admin/class-page.php index e2b662e7e..c9f8960d6 100644 --- a/classes/admin/class-page.php +++ b/classes/admin/class-page.php @@ -211,7 +211,10 @@ public function enqueue_scripts() { [ 'name' => 'progressPlannerSettingsPage', 'data' => [ - 'siteUrl' => \get_site_url(), + 'siteUrl' => \get_site_url(), + 'onboardNonceURL' => \progress_planner()->get_utils__onboard()->get_remote_nonce_url(), + 'onboardAPIUrl' => \progress_planner()->get_utils__onboard()->get_remote_url(), + 'ajaxUrl' => \admin_url( 'admin-ajax.php' ), ], ] ); diff --git a/classes/suggested-tasks/providers/class-settings-saved.php b/classes/suggested-tasks/providers/class-settings-saved.php index 5fe62f14c..85d5ecd52 100644 --- a/classes/suggested-tasks/providers/class-settings-saved.php +++ b/classes/suggested-tasks/providers/class-settings-saved.php @@ -85,4 +85,14 @@ public function add_task_actions( $data = [], $actions = [] ) { return $actions; } + + /** + * Check if the task is completed. + * + * @param string $task_id Optional task ID to check completion for. + * @return bool + */ + public function is_task_completed( $task_id = '' ) { + return false !== \get_option( 'progress_planner_pro_license_key', false ); + } } diff --git a/views/admin-page-settings.php b/views/admin-page-settings.php index 1f7fe5bed..d8ed52066 100644 --- a/views/admin-page-settings.php +++ b/views/admin-page-settings.php @@ -33,6 +33,8 @@ the_view( 'page-settings/settings.php' ); ?> + the_view( 'page-settings/api-status.php' ); ?> +