Skip to content

Commit ce7eb14

Browse files
committed
style: apply ESLint/Prettier auto-fixes and merge duplicate imports
Runs wp-scripts lint-js --fix on the JS sources, resolving 42 of 57 lint issues (mostly Prettier formatting and missing curly braces). Also merges duplicate @wordpress/editor imports in MultiAuthorPlugin.js. Remaining errors require non-trivial structural decisions (experimental WP APIs, JSDoc types, browser globals) and are left for follow-up. Nightshift-Task: lint-fix Nightshift-Ref: https://github.com/marcus/nightshift
1 parent 1bbd00e commit ce7eb14

2 files changed

Lines changed: 140 additions & 44 deletions

File tree

src/components/MultiAuthorPlugin.js

Lines changed: 76 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { useState, useEffect, useCallback } from '@wordpress/element';
2-
import { PluginDocumentSettingPanel } from '@wordpress/editor';
2+
import {
3+
PluginDocumentSettingPanel,
4+
store as editorStore,
5+
} from '@wordpress/editor';
36
import { useSelect } from '@wordpress/data';
47
import { store as coreStore } from '@wordpress/core-data';
5-
import { store as editorStore } from '@wordpress/editor';
68
import { __, sprintf } from '@wordpress/i18n';
79
import apiFetch from '@wordpress/api-fetch';
810
import {
@@ -22,6 +24,10 @@ const NAMESPACE = '/multi-author-posts/v1';
2224

2325
/**
2426
* A single co-author row.
27+
* @param root0
28+
* @param root0.author
29+
* @param root0.canManage
30+
* @param root0.onRemove
2531
*/
2632
function AuthorCard( { author, canManage, onRemove } ) {
2733
return (
@@ -44,7 +50,10 @@ function AuthorCard( { author, canManage, onRemove } ) {
4450
onClick={ () => onRemove( author.id ) }
4551
aria-label={
4652
/* translators: %s: author display name */
47-
sprintf( __( 'Remove %s', 'multi-author-posts' ), author.name )
53+
sprintf(
54+
__( 'Remove %s', 'multi-author-posts' ),
55+
author.name
56+
)
4857
}
4958
>
5059
{ __( 'Remove', 'multi-author-posts' ) }
@@ -56,6 +65,9 @@ function AuthorCard( { author, canManage, onRemove } ) {
5665

5766
/**
5867
* User search + direct-add UI (shown only when the current user can manage co-authors).
68+
* @param root0
69+
* @param root0.postId
70+
* @param root0.onAdd
5971
*/
6072
function DirectAdd( { postId, onAdd } ) {
6173
const [ search, setSearch ] = useState( '' );
@@ -71,7 +83,9 @@ function DirectAdd( { postId, onAdd } ) {
7183
setIsSearching( true );
7284
const controller = new AbortController();
7385
apiFetch( {
74-
path: `${ NAMESPACE }/posts/${ postId }/suggested-authors?search=${ encodeURIComponent( search ) }`,
86+
path: `${ NAMESPACE }/posts/${ postId }/suggested-authors?search=${ encodeURIComponent(
87+
search
88+
) }`,
7589
signal: controller.signal,
7690
} )
7791
.then( ( data ) => {
@@ -104,7 +118,10 @@ function DirectAdd( { postId, onAdd } ) {
104118
label={ __( 'Add existing author', 'multi-author-posts' ) }
105119
value={ search }
106120
onChange={ setSearch }
107-
placeholder={ __( 'Search by name or email…', 'multi-author-posts' ) }
121+
placeholder={ __(
122+
'Search by name or email…',
123+
'multi-author-posts'
124+
) }
108125
/>
109126
{ isSearching && <Spinner /> }
110127
{ suggestions.length > 0 && (
@@ -119,7 +136,12 @@ function DirectAdd( { postId, onAdd } ) {
119136
width={ 28 }
120137
height={ 28 }
121138
/>
122-
<span><TextHighlight text={ user.name } highlight={ search } /></span>
139+
<span>
140+
<TextHighlight
141+
text={ user.name }
142+
highlight={ search }
143+
/>
144+
</span>
123145
</HStack>
124146
<Button
125147
variant="secondary"
@@ -133,17 +155,24 @@ function DirectAdd( { postId, onAdd } ) {
133155
) ) }
134156
</ul>
135157
) }
136-
{ search.length >= 2 && ! isSearching && suggestions.length === 0 && (
137-
<p className="map-no-suggestions">
138-
{ __( 'No matching authors found.', 'multi-author-posts' ) }
139-
</p>
140-
) }
158+
{ search.length >= 2 &&
159+
! isSearching &&
160+
suggestions.length === 0 && (
161+
<p className="map-no-suggestions">
162+
{ __(
163+
'No matching authors found.',
164+
'multi-author-posts'
165+
) }
166+
</p>
167+
) }
141168
</VStack>
142169
);
143170
}
144171

145172
/**
146173
* Invite-link section (shown only when the current user can manage co-authors).
174+
* @param root0
175+
* @param root0.postId
147176
*/
148177
function InviteSection( { postId } ) {
149178
// Plaintext URL is only available in-memory, immediately after creation.
@@ -186,18 +215,24 @@ function InviteSection( { postId } ) {
186215
}, [ postId ] );
187216

188217
const handleCopy = useCallback( () => {
189-
if ( ! inviteUrl ) return;
218+
if ( ! inviteUrl ) {
219+
return;
220+
}
190221
navigator.clipboard?.writeText( inviteUrl ).then( () => {
191222
setCopied( true );
192223
setTimeout( () => setCopied( false ), 2000 );
193224
} );
194225
}, [ inviteUrl ] );
195226

196-
if ( isLoading ) return <Spinner />;
227+
if ( isLoading ) {
228+
return <Spinner />;
229+
}
197230

198231
return (
199232
<VStack spacing={ 2 } className="map-invite-section">
200-
<strong>{ __( 'Shared invite link', 'multi-author-posts' ) }</strong>
233+
<strong>
234+
{ __( 'Shared invite link', 'multi-author-posts' ) }
235+
</strong>
201236
<p className="map-invite-description">
202237
{ __(
203238
'Anyone with this link who is registered on the network can join as a co-author. The link is valid for 24 hours and is only shown once — copy it now.',
@@ -213,7 +248,11 @@ function InviteSection( { postId } ) {
213248
onClick={ ( e ) => e.target.select() }
214249
/>
215250
<HStack justify="flex-start" spacing={ 2 }>
216-
<Button variant="secondary" onClick={ handleCopy } disabled={ copied }>
251+
<Button
252+
variant="secondary"
253+
onClick={ handleCopy }
254+
disabled={ copied }
255+
>
217256
{ copied
218257
? __( 'Copied!', 'multi-author-posts' )
219258
: __( 'Copy link', 'multi-author-posts' ) }
@@ -223,7 +262,10 @@ function InviteSection( { postId } ) {
223262
) }
224263
{ ! inviteUrl && isActive && (
225264
<p className="map-invite-active">
226-
{ __( 'An invite link is active. Regenerate to issue a new one (the previous link will stop working) or revoke it.', 'multi-author-posts' ) }
265+
{ __(
266+
'An invite link is active. Regenerate to issue a new one (the previous link will stop working) or revoke it.',
267+
'multi-author-posts'
268+
) }
227269
</p>
228270
) }
229271
<HStack justify="flex-start" spacing={ 2 }>
@@ -233,7 +275,11 @@ function InviteSection( { postId } ) {
233275
: __( 'Generate invite link', 'multi-author-posts' ) }
234276
</Button>
235277
{ isActive && (
236-
<Button variant="tertiary" isDestructive onClick={ handleRevoke }>
278+
<Button
279+
variant="tertiary"
280+
isDestructive
281+
onClick={ handleRevoke }
282+
>
237283
{ __( 'Revoke', 'multi-author-posts' ) }
238284
</Button>
239285
) }
@@ -263,13 +309,14 @@ export default function MultiAuthorPlugin() {
263309
// Post author and any existing co-author share the same management trust.
264310
// The REST API enforces the same rule server-side.
265311
const canManage =
266-
!! currentUserId && (
267-
currentUserId === postAuthorId ||
268-
coAuthors.some( ( a ) => a.id === currentUserId )
269-
);
312+
!! currentUserId &&
313+
( currentUserId === postAuthorId ||
314+
coAuthors.some( ( a ) => a.id === currentUserId ) );
270315

271316
useEffect( () => {
272-
if ( ! postId ) return;
317+
if ( ! postId ) {
318+
return;
319+
}
273320
setIsLoading( true );
274321
apiFetch( { path: `${ NAMESPACE }/posts/${ postId }/co-authors` } )
275322
.then( ( data ) => {
@@ -299,14 +346,19 @@ export default function MultiAuthorPlugin() {
299346
.catch( ( err ) =>
300347
setError(
301348
err?.message ??
302-
__( 'Could not remove co-author.', 'multi-author-posts' )
349+
__(
350+
'Could not remove co-author.',
351+
'multi-author-posts'
352+
)
303353
)
304354
);
305355
},
306356
[ postId ]
307357
);
308358

309-
if ( ! postId ) return null;
359+
if ( ! postId ) {
360+
return null;
361+
}
310362

311363
return (
312364
<PluginDocumentSettingPanel

tests/js/MultiAuthorPlugin.test.js

Lines changed: 64 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,16 @@ const { useSelect } = require( '@wordpress/data' );
3535

3636
const POST_ID = 42;
3737
const AUTHOR_ID = 1;
38-
const CO_AUTHOR = { id: 2, name: 'Jane Doe', avatar: 'http://example.com/avatar.jpg' };
39-
40-
function setupUseSelect( { currentUserId = AUTHOR_ID, postAuthorId = AUTHOR_ID } = {} ) {
38+
const CO_AUTHOR = {
39+
id: 2,
40+
name: 'Jane Doe',
41+
avatar: 'http://example.com/avatar.jpg',
42+
};
43+
44+
function setupUseSelect( {
45+
currentUserId = AUTHOR_ID,
46+
postAuthorId = AUTHOR_ID,
47+
} = {} ) {
4148
useSelect.mockImplementation( ( selector ) =>
4249
selector( ( storeName ) => {
4350
const map = {
@@ -76,20 +83,26 @@ describe( 'MultiAuthorPlugin', () => {
7683
it( 'renders the Co-Authors panel heading', async () => {
7784
render( <MultiAuthorPlugin /> );
7885
await waitFor( () =>
79-
expect( screen.getByRole( 'heading', { name: /co-authors/i } ) ).toBeInTheDocument()
86+
expect(
87+
screen.getByRole( 'heading', { name: /co-authors/i } )
88+
).toBeInTheDocument()
8089
);
8190
} );
8291

8392
it( 'shows "No co-authors yet" when the list is empty', async () => {
8493
render( <MultiAuthorPlugin /> );
8594
await waitFor( () =>
86-
expect( screen.getByText( /no co-authors yet/i ) ).toBeInTheDocument()
95+
expect(
96+
screen.getByText( /no co-authors yet/i )
97+
).toBeInTheDocument()
8798
);
8899
} );
89100

90101
it( 'renders co-author names after loading', async () => {
91102
apiFetch.mockImplementation( ( { path } ) => {
92-
if ( path.includes( '/invite' ) ) return Promise.resolve( { active: false } );
103+
if ( path.includes( '/invite' ) ) {
104+
return Promise.resolve( { active: false } );
105+
}
93106
return Promise.resolve( [ CO_AUTHOR ] );
94107
} );
95108

@@ -111,24 +124,34 @@ describe( 'MultiAuthorPlugin', () => {
111124
it( 'shows "active" state with Regenerate / Revoke when invite exists', async () => {
112125
apiFetch.mockImplementation( ( { path } ) => {
113126
if ( path.includes( '/invite' ) ) {
114-
return Promise.resolve( { active: true, created: 1000, expires: 2000 } );
127+
return Promise.resolve( {
128+
active: true,
129+
created: 1000,
130+
expires: 2000,
131+
} );
115132
}
116133
return Promise.resolve( [] );
117134
} );
118135

119136
render( <MultiAuthorPlugin /> );
120137
await waitFor( () =>
121138
expect(
122-
screen.getByRole( 'button', { name: /regenerate invite link/i } )
139+
screen.getByRole( 'button', {
140+
name: /regenerate invite link/i,
141+
} )
123142
).toBeInTheDocument()
124143
);
125-
expect( screen.getByRole( 'button', { name: /revoke/i } ) ).toBeInTheDocument();
144+
expect(
145+
screen.getByRole( 'button', { name: /revoke/i } )
146+
).toBeInTheDocument();
126147
} );
127148

128149
it( 'reveals the plaintext URL exactly once, after generate', async () => {
129150
apiFetch.mockImplementation( ( { path, method } ) => {
130151
if ( path.includes( '/invite' ) && method === 'POST' ) {
131-
return Promise.resolve( { invite_url: 'http://example.com/?map_invite=plain' } );
152+
return Promise.resolve( {
153+
invite_url: 'http://example.com/?map_invite=plain',
154+
} );
132155
}
133156
if ( path.includes( '/invite' ) ) {
134157
return Promise.resolve( { active: false } );
@@ -146,7 +169,9 @@ describe( 'MultiAuthorPlugin', () => {
146169
);
147170

148171
await act( async () => {
149-
await user.click( screen.getByRole( 'button', { name: /generate invite link/i } ) );
172+
await user.click(
173+
screen.getByRole( 'button', { name: /generate invite link/i } )
174+
);
150175
} );
151176

152177
expect(
@@ -160,19 +185,30 @@ describe( 'MultiAuthorPlugin', () => {
160185
render( <MultiAuthorPlugin /> );
161186
await waitFor( () =>
162187
// Co-authors list loads
163-
expect( screen.queryByText( /no co-authors yet/i ) ).toBeInTheDocument()
188+
expect(
189+
screen.queryByText( /no co-authors yet/i )
190+
).toBeInTheDocument()
164191
);
165192

166-
expect( screen.queryByRole( 'button', { name: /generate invite link/i } ) ).toBeNull();
193+
expect(
194+
screen.queryByRole( 'button', { name: /generate invite link/i } )
195+
).toBeNull();
167196
expect( screen.queryByRole( 'searchbox' ) ).toBeNull();
168197
} );
169198

170199
it( 'shows management controls to a co-author of the post', async () => {
171200
const CO_AUTHOR_ID = 99;
172-
setupUseSelect( { currentUserId: CO_AUTHOR_ID, postAuthorId: AUTHOR_ID } );
201+
setupUseSelect( {
202+
currentUserId: CO_AUTHOR_ID,
203+
postAuthorId: AUTHOR_ID,
204+
} );
173205
apiFetch.mockImplementation( ( { path } ) => {
174-
if ( path.includes( '/invite' ) ) return Promise.resolve( { active: false } );
175-
return Promise.resolve( [ { id: CO_AUTHOR_ID, name: 'Me', avatar: 'x' } ] );
206+
if ( path.includes( '/invite' ) ) {
207+
return Promise.resolve( { active: false } );
208+
}
209+
return Promise.resolve( [
210+
{ id: CO_AUTHOR_ID, name: 'Me', avatar: 'x' },
211+
] );
176212
} );
177213

178214
render( <MultiAuthorPlugin /> );
@@ -186,8 +222,12 @@ describe( 'MultiAuthorPlugin', () => {
186222

187223
it( 'calls DELETE when Remove button is clicked', async () => {
188224
apiFetch.mockImplementation( ( { path, method } ) => {
189-
if ( method === 'DELETE' ) return Promise.resolve( {} );
190-
if ( path.includes( '/invite' ) ) return Promise.resolve( { active: false } );
225+
if ( method === 'DELETE' ) {
226+
return Promise.resolve( {} );
227+
}
228+
if ( path.includes( '/invite' ) ) {
229+
return Promise.resolve( { active: false } );
230+
}
191231
return Promise.resolve( [ CO_AUTHOR ] );
192232
} );
193233

@@ -199,13 +239,17 @@ describe( 'MultiAuthorPlugin', () => {
199239
);
200240

201241
await act( async () => {
202-
await user.click( screen.getByRole( 'button', { name: /remove jane doe/i } ) );
242+
await user.click(
243+
screen.getByRole( 'button', { name: /remove jane doe/i } )
244+
);
203245
} );
204246

205247
expect( apiFetch ).toHaveBeenCalledWith(
206248
expect.objectContaining( {
207249
method: 'DELETE',
208-
path: expect.stringContaining( `/co-authors/${ CO_AUTHOR.id }` ),
250+
path: expect.stringContaining(
251+
`/co-authors/${ CO_AUTHOR.id }`
252+
),
209253
} )
210254
);
211255
} );

0 commit comments

Comments
 (0)