Skip to content

Commit 804f88e

Browse files
authored
Merge pull request #78 from newfold-labs/update/task-complete-action
Update/task complete action
2 parents 8c2fa76 + b9bc400 commit 804f88e

File tree

10 files changed

+68
-89
lines changed

10 files changed

+68
-89
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<?php return array('dependencies' => array('lodash', 'react', 'react-jsx-runtime', 'wp-api-fetch', 'wp-dom-ready', 'wp-element', 'wp-i18n'), 'version' => '5a1b36f2c467190cfbad');
1+
<?php return array('dependencies' => array('lodash', 'react', 'react-jsx-runtime', 'wp-api-fetch', 'wp-dom-ready', 'wp-element', 'wp-i18n'), 'version' => '6fa3e01c448e3b46a1a0');

build/next-steps-portal/bundle.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<?php return array('dependencies' => array('lodash', 'react', 'react-jsx-runtime', 'wp-api-fetch', 'wp-dom-ready', 'wp-element', 'wp-i18n'), 'version' => '9307352588a77f05b7f9');
1+
<?php return array('dependencies' => array('lodash', 'react', 'react-jsx-runtime', 'wp-api-fetch', 'wp-dom-ready', 'wp-element', 'wp-i18n'), 'version' => 'a4df2b5ae69fbc209752');

build/next-steps-widget/bundle.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

includes/StepsApi.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public function register_routes() {
8080
$this->rest_base . '/status',
8181
array(
8282
'methods' => \WP_REST_Server::EDITABLE,
83-
'callback' => array( $this, 'update_step_status' ),
83+
'callback' => array( $this, 'update_task_status' ),
8484
'permission_callback' => function () {
8585
return current_user_can( 'manage_options' );
8686
},
@@ -360,12 +360,12 @@ public static function add_steps( $new_tasks ) {
360360
}
361361

362362
/**
363-
* Update a step status.
363+
* Update a task status.
364364
*
365365
* @param \WP_REST_Request $request The REST request object.
366366
* @return WP_REST_Response|WP_Error The response object on success, or WP_Error on failure.
367367
*/
368-
public static function update_step_status( \WP_REST_Request $request ) {
368+
public static function update_task_status( \WP_REST_Request $request ) {
369369
$plan = $request->get_param( 'plan' );
370370
$track = $request->get_param( 'track' );
371371
$section = $request->get_param( 'section' );
@@ -388,9 +388,9 @@ public static function update_step_status( \WP_REST_Request $request ) {
388388
}
389389

390390
// Get the updated plan
391-
$plan = PlanManager::get_current_plan();
391+
// $plan = PlanManager::get_current_plan();
392392

393-
return new WP_REST_Response( $plan->to_array(), 200 );
393+
return new WP_REST_Response( true, 200 );
394394
}
395395

396396
/**

src/components/nextSteps/index.js

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,9 @@ const taskUpdateWrapper = ( data, passError, thenCallback ) => {
3838
data,
3939
} )
4040
.then( ( response ) => {
41-
// console.log( 'Response from taskUpdateWrapper:', response );
4241
thenCallback( response );
4342
} )
4443
.catch( ( error ) => {
45-
// console.error( 'Error from taskUpdateWrapper:', error );
4644
passError( error );
4745
} );
4846
};
@@ -64,11 +62,9 @@ const sectionUpdateWrapper = ( data, passError, thenCallback ) => {
6462
data,
6563
} )
6664
.then( ( response ) => {
67-
// console.log( 'Section update response:', response );
6865
thenCallback( response );
6966
} )
7067
.catch( ( error ) => {
71-
// console.error( 'Error updating section:', error );
7268
passError( error );
7369
} );
7470
};
@@ -90,11 +86,9 @@ const trackUpdateWrapper = ( data, passError, thenCallback ) => {
9086
data,
9187
} )
9288
.then( ( response ) => {
93-
// console.log( 'Track update response:', response );
9489
thenCallback( response );
9590
} )
9691
.catch( ( error ) => {
97-
// console.error( 'Error updating track:', error );
9892
passError( error );
9993
} );
10094
};
@@ -104,7 +98,7 @@ export const NextSteps = () => {
10498
const [ showDismissed, setShowDismissed ] = useState( true );
10599
const [ showControls, setShowControls ] = useState( false );
106100

107-
const taskUpdateCallback = ( track, section, id, status ) => {
101+
const taskUpdateCallback = ( track, section, id, status, errorCallback, successCallback ) => {
108102
const data = {
109103
plan: plan.id,
110104
track,
@@ -115,21 +109,16 @@ export const NextSteps = () => {
115109
taskUpdateWrapper(
116110
data,
117111
( error ) => {
118-
// TODO handle error better
119-
// console.error( 'Error updating step:', error );
112+
errorCallback( error );
120113
},
121114
( response ) => {
122-
// The response is the full plan object, not wrapped in a plan property
123-
// console.log( 'Task update response:', response );
124-
window.NewfoldNextSteps = response;
125-
setPlan( response );
115+
// Nothing action needed here since the task update is handled in the task component
116+
successCallback( response );
126117
}
127118
);
128119
};
129120

130-
const sectionOpenCallback = ( section, open ) => {
131-
// console.log( 'Section open callback:', section, open );
132-
121+
const sectionOpenCallback = ( section, open ) => {
133122
// Find the track that contains this section
134123
let trackId = null;
135124
if ( plan && plan.tracks ) {
@@ -142,7 +131,7 @@ export const NextSteps = () => {
142131
}
143132

144133
if ( ! trackId ) {
145-
// console.error( 'Could not find track for section:', section );
134+
// Could not find track for intendend section
146135
return;
147136
}
148137

@@ -165,8 +154,6 @@ export const NextSteps = () => {
165154
};
166155

167156
const trackOpenCallback = ( track, open ) => {
168-
// console.log( 'Track open callback:', track, open );
169-
170157
const data = {
171158
plan: plan.id,
172159
track: track,

src/components/section/index.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,10 @@ export const Section = ( props ) => {
7575
{ total > 0 && <ProgressBar completed={ completed } total={ total } /> }
7676
</summary>
7777
<div className="nfd-section-steps">
78-
{ section.tasks.map( ( step ) => (
78+
{ section.tasks.map( ( task ) => (
7979
<Task
80-
key={ step.id }
81-
step={ step }
80+
key={ task.id }
81+
task={ task }
8282
taskUpdateCallback={ taskUpdateCallback }
8383
showDismissed={ showDismissed }
8484
track={ track }

src/components/task/index.js

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,48 @@
11
import { Title } from '@newfold/ui-component-library';
22
import { __ } from '@wordpress/i18n';
3+
import { useState } from '@wordpress/element';
34
import { doneIcon, hideIcon, showIcon, goIcon, circleDashedIcon, circleIcon } from '../icons';
45

56
export const Task = ( props ) => {
67
const {
7-
step,
8+
task,
89
taskUpdateCallback,
910
track,
1011
section,
1112
showDismissed,
1213
...restProps
1314
} = props;
1415

15-
// Destructure step properties
16+
// Destructure task properties
1617
const {
1718
id,
18-
// description = '',
1919
title = '',
20-
status,
2120
href,
2221
data_attributes = {}
23-
} = step;
22+
} = task;
23+
// task status uses state to track the current status
24+
const [ status, setStatus ] = useState( task.status );
25+
26+
const updateStatus = ( newStatus ) => {
27+
const currentStatus = status;
28+
setStatus( newStatus ); // for immediate UI feedback
29+
// update task status via API
30+
taskUpdateCallback(
31+
track,
32+
section,
33+
id,
34+
newStatus,
35+
( error ) => {
36+
// undo status update on error
37+
setStatus( currentStatus );
38+
console.error( 'Error updating task status. Please, try reloading the page to load the latest data.', error );
39+
},
40+
( response ) => {
41+
// update status on success
42+
setStatus( newStatus ); // redundant since we already set it above
43+
}
44+
);
45+
};
2446

2547
const getHref = () => {
2648
let hrefValue = href;
@@ -97,7 +119,7 @@ export const Task = ( props ) => {
97119
data-nfd-event-category="nextsteps_step"
98120
data-nfd-event-key={ id }
99121
onClick={ ( e ) =>
100-
taskUpdateCallback( track, section, id, 'done' )
122+
updateStatus( 'done' )
101123
}
102124
title={ __(
103125
'Mark Complete',
@@ -115,12 +137,7 @@ export const Task = ( props ) => {
115137
data-nfd-event-category="nextsteps_step"
116138
data-nfd-event-key={ id }
117139
onClick={ ( e ) =>
118-
taskUpdateCallback(
119-
track,
120-
section,
121-
id,
122-
'dismissed'
123-
)
140+
updateStatus( 'dismissed' )
124141
}
125142
title={ __( 'Skip', 'wp-module-next-steps' ) }
126143
>
@@ -153,7 +170,7 @@ export const Task = ( props ) => {
153170
data-nfd-event-category="nextsteps_step"
154171
data-nfd-event-key={ id }
155172
onClick={ ( e ) =>
156-
taskUpdateCallback( track, section, id, 'new' )
173+
updateStatus( 'new' )
157174
}
158175
title={ __( 'Restart', 'wp-module-next-steps' ) }
159176
>
@@ -176,7 +193,7 @@ export const Task = ( props ) => {
176193
data-nfd-event-category="nextsteps_step"
177194
data-nfd-event-key={ id }
178195
onClick={ ( e ) =>
179-
taskUpdateCallback( track, section, id, 'new' )
196+
updateStatus( 'new' )
180197
}
181198
title={ __( 'Unskip', 'wp-module-next-steps' ) }
182199
>
@@ -191,7 +208,7 @@ export const Task = ( props ) => {
191208
data-nfd-event-category="nextsteps_step"
192209
data-nfd-event-key={ id }
193210
onClick={ ( e ) =>
194-
taskUpdateCallback( track, section, id, 'new' )
211+
updateStatus( 'new' )
195212
}
196213
title={ __( 'Unskip', 'wp-module-next-steps' ) }
197214
>

tests/cypress/integration/next-steps-widget.cy.js

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@ describe( 'Next Steps Dashboard Widget', { testIsolation: true }, () => {
1717
before( () => {
1818
// Reset Next Steps data to ensure clean state for tests
1919
resetNextStepsData();
20-
wpCli( 'rewrite structure "/%postname%/"', { failOnNonZeroExit: false } );
21-
wpCli( 'rewrite flush', { failOnNonZeroExit: false } );
2220
} );
2321

2422
beforeEach( () => {
@@ -239,32 +237,4 @@ describe( 'Next Steps Dashboard Widget', { testIsolation: true }, () => {
239237
cy.get( '@newTask' ).find( '.nfd-nextsteps-button-link' ).should( 'have.attr', 'data-nfd-event-key' );
240238
} );
241239

242-
// New test to verify version handling and merge functionality
243-
it( 'handles versioned data correctly', () => {
244-
// Ensure Proper Visibility First
245-
ensureTrackOpen( 0 );
246-
ensureSectionExpanded( 0, 0 );
247-
248-
// Complete a task to create some user state
249-
getTaskByStatus( 'new' ).then( ( task ) => {
250-
completeTask( cy.wrap( task ) );
251-
} );
252-
253-
// Verify the task is completed
254-
getTaskByStatus( 'done' ).should( 'have.length.greaterThan', 0 );
255-
256-
// Refresh the page to trigger potential merge logic
257-
cy.reload();
258-
259-
// Wait for app to reload
260-
waitForNextStepsApp();
261-
262-
// Verify the completed task status is preserved after reload
263-
getTaskByStatus( 'done' ).should( 'have.length.greaterThan', 0 );
264-
265-
// Verify the app still functions normally
266-
cy.get( '.nfd-track' ).should( 'have.length.greaterThan', 0 );
267-
cy.get( '.nfd-section' ).should( 'have.length.greaterThan', 0 );
268-
cy.get( '.nfd-nextsteps-step-container' ).should( 'have.length.greaterThan', 0 );
269-
} );
270240
} );

tests/cypress/wp-module-support/next-steps-helpers.cy.js

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -170,11 +170,25 @@ export const getTaskByStatus = ( status ) => {
170170
*/
171171
export const completeTask = ( task ) => {
172172
cy.log( '✅ completeTask called' );
173+
174+
// Intercept the task status update API call (since endpoint depends on permalinks)
175+
cy.intercept(
176+
{
177+
method: 'POST',
178+
url: /newfold-next-steps(\/|%2F)v1(\/|%2F)steps(\/|%2F)status/,
179+
},
180+
{
181+
statusCode: 200,
182+
body: true
183+
}
184+
).as( 'updateTaskStatus' );
173185

174186
// Click the completion button and verify the task transitions to completed state
175187
task
188+
.scrollIntoView()
176189
.should( 'exist' )
177190
.and( 'be.visible' )
191+
.and( 'not.be.disabled' )
178192
.then( ( $task ) => {
179193
// Get task container for verification
180194
const $container = $task.closest( '.nfd-nextsteps-step-container' );
@@ -189,19 +203,10 @@ export const completeTask = ( task ) => {
189203
.and( 'not.be.disabled' )
190204
.click( { force: true } );
191205

192-
// CRITICAL: Verify the task actually became completed
193-
// This addresses the CI issue where DOM doesn't update fast enough
194-
if ( taskId ) {
195-
// Wait for the task to transition to completed state
196-
cy.get( `#${taskId} .nfd-nextsteps-step-done`, { timeout: 15000 } )
197-
.should( 'exist' );
198-
cy.log( `✅ Task ${taskId} verified as completed` );
199-
} else {
200-
// Fallback: ensure at least one completed task exists
201-
cy.get( '.nfd-nextsteps-step-done', { timeout: 15000 } )
202-
.should( 'exist' );
203-
cy.log( `✅ Task completion verified (fallback)` );
204-
}
206+
cy.wait( '@updateTaskStatus' );
207+
208+
cy.get( `#${taskId} .nfd-nextsteps-step-done` ).should( 'exist' );
209+
cy.log( `✅ Task ${taskId} verified as completed` );
205210
} );
206211

207212
cy.log( `🎯 Task completion process finished` );

0 commit comments

Comments
 (0)