mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-08-30 05:00:51 +08:00
Settings UI: Add functionality to mark todos as complete on click
This commit is contained in:
parent
05c73303af
commit
04f0f45233
12 changed files with 163 additions and 29 deletions
|
@ -1,6 +1,6 @@
|
|||
import { selectTab, TAB_IDS } from '../../../utils/tabSelector';
|
||||
import { useEffect, useState } from '@wordpress/element';
|
||||
import { useSelect } from '@wordpress/data';
|
||||
import { useDispatch, useSelect } from '@wordpress/data';
|
||||
import { STORE_NAME as TODOS_STORE_NAME } from '../../../data/todos';
|
||||
|
||||
const TodoSettingsBlock = ( {
|
||||
|
@ -21,6 +21,8 @@ const TodoSettingsBlock = ( {
|
|||
[]
|
||||
);
|
||||
|
||||
const { completeOnClick } = useDispatch( TODOS_STORE_NAME );
|
||||
|
||||
useEffect( () => {
|
||||
if ( dismissedTodos.length === 0 ) {
|
||||
setDismissingIds( new Set() );
|
||||
|
@ -41,6 +43,26 @@ const TodoSettingsBlock = ( {
|
|||
}, 300 );
|
||||
};
|
||||
|
||||
const handleClick = async ( todo ) => {
|
||||
if ( todo.action.type === 'tab' ) {
|
||||
const tabId = TAB_IDS[ todo.action.tab.toUpperCase() ];
|
||||
await selectTab( tabId, todo.action.section );
|
||||
} else if ( todo.action.type === 'external' ) {
|
||||
window.open( todo.action.url, '_blank' );
|
||||
// If it has completeOnClick flag, trigger the action
|
||||
if ( todo.action.completeOnClick === true ) {
|
||||
await completeOnClick( todo.id );
|
||||
}
|
||||
}
|
||||
|
||||
if ( todo.action.modal ) {
|
||||
setActiveModal( todo.action.modal );
|
||||
}
|
||||
if ( todo.action.highlight ) {
|
||||
setActiveHighlight( todo.action.highlight );
|
||||
}
|
||||
};
|
||||
|
||||
// Filter out dismissed todos for display
|
||||
const visibleTodos = todosData.filter(
|
||||
( todo ) => ! dismissedTodos.includes( todo.id )
|
||||
|
@ -59,22 +81,7 @@ const TodoSettingsBlock = ( {
|
|||
isCompleted={ completedTodos.includes( todo.id ) }
|
||||
isDismissing={ dismissingIds.has( todo.id ) }
|
||||
onDismiss={ ( e ) => handleDismiss( todo.id, e ) }
|
||||
onClick={ async () => {
|
||||
if ( todo.action.type === 'tab' ) {
|
||||
const tabId =
|
||||
TAB_IDS[ todo.action.tab.toUpperCase() ];
|
||||
await selectTab( tabId, todo.action.section );
|
||||
} else if ( todo.action.type === 'external' ) {
|
||||
window.open( todo.action.url, '_blank' );
|
||||
}
|
||||
|
||||
if ( todo.action.modal ) {
|
||||
setActiveModal( todo.action.modal );
|
||||
}
|
||||
if ( todo.action.highlight ) {
|
||||
setActiveHighlight( todo.action.highlight );
|
||||
}
|
||||
} }
|
||||
onClick={ () => handleClick( todo ) }
|
||||
/>
|
||||
) ) }
|
||||
</div>
|
||||
|
|
|
@ -17,4 +17,5 @@ export default {
|
|||
DO_FETCH_TODOS: 'TODOS:DO_FETCH_TODOS',
|
||||
DO_PERSIST_DATA: 'TODOS:DO_PERSIST_DATA',
|
||||
DO_RESET_DISMISSED_TODOS: 'TODOS:DO_RESET_DISMISSED_TODOS',
|
||||
DO_COMPLETE_ONCLICK: 'TODOS:DO_COMPLETE_ONCLICK',
|
||||
};
|
||||
|
|
|
@ -39,8 +39,7 @@ export const resetDismissedTodos = function* () {
|
|||
const result = yield { type: ACTION_TYPES.DO_RESET_DISMISSED_TODOS };
|
||||
|
||||
if ( result && result.success ) {
|
||||
// After successful reset, fetch fresh todos
|
||||
yield fetchTodos();
|
||||
yield setDismissedTodos( [] );
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -50,3 +49,19 @@ export const setCompletedTodos = ( completedTodos ) => ( {
|
|||
type: ACTION_TYPES.SET_COMPLETED_TODOS,
|
||||
payload: completedTodos,
|
||||
} );
|
||||
|
||||
export const completeOnClick = function* ( todoId ) {
|
||||
const result = yield {
|
||||
type: ACTION_TYPES.DO_COMPLETE_ONCLICK,
|
||||
todoId,
|
||||
};
|
||||
|
||||
if ( result && result.success ) {
|
||||
// Set transient completed state for visual feedback
|
||||
const currentTransientCompleted =
|
||||
yield select( STORE_NAME ).getCompletedTodos();
|
||||
yield setCompletedTodos( [ ...currentTransientCompleted, todoId ] );
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
|
|
@ -9,3 +9,4 @@ export const REST_PATH = '/wc/v3/wc_paypal/todos';
|
|||
export const REST_PERSIST_PATH = '/wc/v3/wc_paypal/todos';
|
||||
export const REST_RESET_DISMISSED_TODOS_PATH =
|
||||
'/wc/v3/wc_paypal/reset-dismissed-todos';
|
||||
export const REST_COMPLETE_ONCLICK_PATH = '/wc/v3/wc_paypal/complete-onclick';
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
REST_PATH,
|
||||
REST_PERSIST_PATH,
|
||||
REST_RESET_DISMISSED_TODOS_PATH,
|
||||
REST_COMPLETE_ONCLICK_PATH,
|
||||
} from './constants';
|
||||
import ACTION_TYPES from './action-types';
|
||||
|
||||
|
@ -44,4 +45,21 @@ export const controls = {
|
|||
};
|
||||
}
|
||||
},
|
||||
async [ ACTION_TYPES.DO_COMPLETE_ONCLICK ]( { todoId } ) {
|
||||
try {
|
||||
const response = await apiFetch( {
|
||||
path: REST_COMPLETE_ONCLICK_PATH,
|
||||
method: 'POST',
|
||||
data: { todoId },
|
||||
} );
|
||||
|
||||
return response;
|
||||
} catch ( e ) {
|
||||
return {
|
||||
success: false,
|
||||
error: e,
|
||||
message: e.message,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
@ -28,6 +28,7 @@ const defaultTransient = Object.freeze( {
|
|||
const defaultPersistent = Object.freeze( {
|
||||
todos: [],
|
||||
dismissedTodos: [],
|
||||
completedOnClickTodos: [],
|
||||
} );
|
||||
|
||||
// Reducer logic.
|
||||
|
|
|
@ -20,6 +20,7 @@ use WooCommerce\PayPalCommerce\Settings\Data\TodosModel;
|
|||
use WooCommerce\PayPalCommerce\Settings\Data\Definition\TodosDefinition;
|
||||
use WooCommerce\PayPalCommerce\Settings\Endpoint\AuthenticationRestEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Settings\Endpoint\CommonRestEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Settings\Endpoint\CompleteOnClickEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Settings\Endpoint\LoginLinkRestEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Settings\Endpoint\OnboardingRestEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Settings\Endpoint\PayLaterMessagingEndpoint;
|
||||
|
@ -265,7 +266,8 @@ return array(
|
|||
},
|
||||
'settings.data.definition.todos' => static function ( ContainerInterface $container ) : TodosDefinition {
|
||||
return new TodosDefinition(
|
||||
$container->get( 'settings.service.todos_eligibilities' )
|
||||
$container->get( 'settings.service.todos_eligibilities' ),
|
||||
$container->get( 'settings.data.general' )
|
||||
);
|
||||
},
|
||||
'settings.service.todos_eligibilities' => static function( ContainerInterface $container ): TodosEligibilityService {
|
||||
|
@ -314,4 +316,7 @@ return array(
|
|||
'settings.rest.reset_dismissed_todos' => static function( ContainerInterface $container ): ResetDismissedTodosEndpoint {
|
||||
return new ResetDismissedTodosEndpoint();
|
||||
},
|
||||
'settings.rest.complete_onclick' => static function( ContainerInterface $container ): CompleteOnClickEndpoint {
|
||||
return new CompleteOnClickEndpoint();
|
||||
},
|
||||
);
|
||||
|
|
|
@ -10,6 +10,7 @@ declare(strict_types=1);
|
|||
namespace WooCommerce\PayPalCommerce\Settings\Data\Definition;
|
||||
|
||||
use WooCommerce\PayPalCommerce\Settings\Service\TodosEligibilityService;
|
||||
use WooCommerce\PayPalCommerce\Settings\Data\GeneralSettings;
|
||||
|
||||
/**
|
||||
* Class TodosDefinition
|
||||
|
@ -26,13 +27,25 @@ class TodosDefinition {
|
|||
*/
|
||||
protected TodosEligibilityService $eligibilities;
|
||||
|
||||
/**
|
||||
* The general settings service.
|
||||
*
|
||||
* @var GeneralSettings
|
||||
*/
|
||||
protected GeneralSettings $settings;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param TodosEligibilityService $eligibilities The todos eligibility service.
|
||||
* @param GeneralSettings $settings The general settings service.
|
||||
*/
|
||||
public function __construct( TodosEligibilityService $eligibilities ) {
|
||||
public function __construct(
|
||||
TodosEligibilityService $eligibilities,
|
||||
GeneralSettings $settings
|
||||
) {
|
||||
$this->eligibilities = $eligibilities;
|
||||
$this->settings = $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -110,9 +123,11 @@ class TodosDefinition {
|
|||
'description' => __( 'To enable Apple Pay, you must register your domain with PayPal', 'woocommerce-paypal-payments' ),
|
||||
'isEligible' => $eligibility_checks['register_domain_apple_pay'],
|
||||
'action' => array(
|
||||
'type' => 'tab',
|
||||
'tab' => 'overview',
|
||||
'section' => 'apple_pay',
|
||||
'type' => 'external',
|
||||
'url' => $this->settings->is_sandbox_merchant()
|
||||
? 'https://www.sandbox.paypal.com/uccservicing/apm/applepay'
|
||||
: 'https://www.paypal.com/uccservicing/apm/applepay',
|
||||
'completeOnClick' => true,
|
||||
),
|
||||
),
|
||||
'add_digital_wallets' => array(
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Settings\Endpoint;
|
||||
|
||||
use WP_REST_Server;
|
||||
use WP_REST_Response;
|
||||
use WP_REST_Request;
|
||||
|
||||
class CompleteOnClickEndpoint extends RestEndpoint {
|
||||
protected $rest_base = 'complete-onclick';
|
||||
|
||||
public function register_routes(): void {
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/' . $this->rest_base,
|
||||
array(
|
||||
'methods' => WP_REST_Server::EDITABLE,
|
||||
'callback' => array( $this, 'complete_onclick' ),
|
||||
'permission_callback' => array( $this, 'check_permission' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function complete_onclick( WP_REST_Request $request ): WP_REST_Response {
|
||||
$todo_id = $request->get_param( 'todoId' );
|
||||
|
||||
if ( ! $todo_id ) {
|
||||
return $this->return_error( __( 'Todo ID is required.', 'woocommerce-paypal-payments' ) );
|
||||
}
|
||||
|
||||
$settings = get_option( 'ppcp-settings', array() );
|
||||
|
||||
if ( ! isset( $settings['completedOnClickTodos'] ) ) {
|
||||
$settings['completedOnClickTodos'] = array();
|
||||
}
|
||||
|
||||
if ( ! in_array( $todo_id, $settings['completedOnClickTodos'] ) ) {
|
||||
$settings['completedOnClickTodos'][] = $todo_id;
|
||||
$update_result = update_option( 'ppcp-settings', $settings );
|
||||
|
||||
if ( ! $update_result ) {
|
||||
return $this->return_error( __( 'Failed to mark todo as completed on click.', 'woocommerce-paypal-payments' ) );
|
||||
}
|
||||
}
|
||||
|
||||
return $this->return_success(
|
||||
array(
|
||||
'message' => __( 'Todo marked as completed on click successfully.', 'woocommerce-paypal-payments' ),
|
||||
'todoId' => $todo_id,
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -57,7 +57,11 @@ class ResetDismissedTodosEndpoint extends RestEndpoint {
|
|||
$settings = get_option( 'ppcp-settings', array() );
|
||||
|
||||
$settings['dismissedTodos'] = array();
|
||||
$update_result = update_option( 'ppcp-settings', $settings );
|
||||
|
||||
// Clear the completedOnClickTodos for testing purposes.
|
||||
// $settings['completedOnClickTodos'] = array();
|
||||
|
||||
$update_result = update_option( 'ppcp-settings', $settings );
|
||||
|
||||
if ( ! $update_result ) {
|
||||
return $this->return_error( __( 'Failed to reset dismissed todos.', 'woocommerce-paypal-payments' ) );
|
||||
|
|
|
@ -103,11 +103,22 @@ class TodosRestEndpoint extends RestEndpoint {
|
|||
* @return WP_REST_Response The response containing todos data.
|
||||
*/
|
||||
public function get_todos(): WP_REST_Response {
|
||||
$settings = get_option( 'ppcp-settings', array() );
|
||||
$dismissed_ids = $settings['dismissedTodos'] ?? array();
|
||||
$settings = get_option( 'ppcp-settings', array() );
|
||||
$dismissed_ids = $settings['dismissedTodos'] ?? array();
|
||||
$completed_onclick_ids = $settings['completedOnClickTodos'] ?? array();
|
||||
|
||||
$todos = array();
|
||||
foreach ( $this->todos_definition->get() as $id => $todo ) {
|
||||
// Skip if todo has completeOnClick flag and is in completed list
|
||||
if (
|
||||
in_array( $id, $completed_onclick_ids, true ) &&
|
||||
isset( $todo['action']['completeOnClick'] ) &&
|
||||
$todo['action']['completeOnClick'] === true
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check eligibility and add to todos if eligible
|
||||
if ( $todo['isEligible']() ) {
|
||||
$todos[] = array_merge(
|
||||
array( 'id' => $id ),
|
||||
|
@ -118,8 +129,9 @@ class TodosRestEndpoint extends RestEndpoint {
|
|||
|
||||
return $this->return_success(
|
||||
array(
|
||||
'todos' => $todos,
|
||||
'dismissedTodos' => $dismissed_ids,
|
||||
'todos' => $todos,
|
||||
'dismissedTodos' => $dismissed_ids,
|
||||
'completedOnClickTodos' => $completed_onclick_ids,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -240,6 +240,7 @@ class SettingsModule implements ServiceModule, ExecutableModule {
|
|||
'todos' => $container->get( 'settings.rest.todos' ),
|
||||
'reset_dismissed_todos' => $container->get( 'settings.rest.reset_dismissed_todos' ),
|
||||
'pay_later_messaging' => $container->get( 'settings.rest.pay_later_messaging' ),
|
||||
'complete_onclick' => $container->get( 'settings.rest.complete_onclick' ),
|
||||
);
|
||||
|
||||
foreach ( $endpoints as $endpoint ) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue