Skip to content

Commit 2f7c72a

Browse files
committed
Componentise view actions and use them in header on mobile
1 parent 6f18d1e commit 2f7c72a

File tree

4 files changed

+251
-178
lines changed

4 files changed

+251
-178
lines changed
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
/**
2+
* External dependencies
3+
*/
4+
import { Button } from '@wordpress/components';
5+
import { useRegistry } from '@wordpress/data';
6+
import { useCallback, useState } from '@wordpress/element';
7+
/**
8+
* Internal dependencies
9+
*/
10+
import {
11+
markAsSpamAction,
12+
markAsNotSpamAction,
13+
moveToTrashAction,
14+
restoreAction,
15+
deleteAction,
16+
} from '../../inbox/dataviews/actions';
17+
/**
18+
* Types
19+
*/
20+
import type { FormResponse } from '../../../types';
21+
22+
type ResponseNavigationProps = {
23+
onActionComplete?: ( id: string ) => void;
24+
response: FormResponse;
25+
};
26+
27+
const ResponseActions = ( {
28+
onActionComplete,
29+
response,
30+
}: ResponseNavigationProps ): JSX.Element => {
31+
const [ isMarkingAsSpam, setIsMarkingAsSpam ] = useState( false );
32+
const [ isMarkingAsNotSpam, setIsMarkingAsNotSpam ] = useState( false );
33+
const [ isMovingToTrash, setIsMovingToTrash ] = useState( false );
34+
const [ isRestoring, setIsRestoring ] = useState( false );
35+
const [ isDeleting, setIsDeleting ] = useState( false );
36+
37+
const registry = useRegistry();
38+
39+
const handleMarkAsSpam = useCallback( async () => {
40+
setIsMarkingAsSpam( true );
41+
await markAsSpamAction.callback( [ response ], { registry } );
42+
setIsMarkingAsSpam( false );
43+
onActionComplete?.( response.id.toString() );
44+
}, [ response, registry, onActionComplete ] );
45+
46+
const handleMarkAsNotSpam = useCallback( async () => {
47+
setIsMarkingAsNotSpam( true );
48+
await markAsNotSpamAction.callback( [ response ], { registry } );
49+
setIsMarkingAsNotSpam( false );
50+
onActionComplete?.( response.id.toString() );
51+
}, [ response, registry, onActionComplete ] );
52+
53+
const handleMoveToTrash = useCallback( async () => {
54+
setIsMovingToTrash( true );
55+
await moveToTrashAction.callback( [ response ], { registry } );
56+
setIsMovingToTrash( false );
57+
onActionComplete?.( response.id.toString() );
58+
}, [ response, registry, onActionComplete ] );
59+
60+
const handleRestore = useCallback( async () => {
61+
setIsRestoring( true );
62+
await restoreAction.callback( [ response ], { registry } );
63+
setIsRestoring( false );
64+
onActionComplete?.( response.id.toString() );
65+
}, [ response, registry, onActionComplete ] );
66+
67+
const handleDelete = useCallback( async () => {
68+
setIsDeleting( true );
69+
await deleteAction.callback( [ response ], { registry } );
70+
setIsDeleting( false );
71+
onActionComplete?.( response.id.toString() );
72+
}, [ response, registry, onActionComplete ] );
73+
74+
switch ( response.status ) {
75+
case 'spam':
76+
return (
77+
<>
78+
<Button
79+
variant="tertiary"
80+
onClick={ handleMarkAsNotSpam }
81+
isBusy={ isMarkingAsNotSpam }
82+
showTooltip={ true }
83+
label={ markAsNotSpamAction.label }
84+
iconSize={ 24 }
85+
icon={ markAsNotSpamAction.icon }
86+
size="compact"
87+
></Button>
88+
<Button
89+
variant="tertiary"
90+
onClick={ handleMoveToTrash }
91+
isBusy={ isMovingToTrash }
92+
showTooltip={ true }
93+
label={ moveToTrashAction.label }
94+
iconSize={ 24 }
95+
icon={ moveToTrashAction.icon }
96+
size="compact"
97+
></Button>
98+
</>
99+
);
100+
101+
case 'trash':
102+
return (
103+
<>
104+
<Button
105+
variant="tertiary"
106+
onClick={ handleRestore }
107+
isBusy={ isRestoring }
108+
showTooltip={ true }
109+
label={ restoreAction.label }
110+
iconSize={ 24 }
111+
icon={ restoreAction.icon }
112+
size="compact"
113+
></Button>
114+
<Button
115+
variant="tertiary"
116+
onClick={ handleDelete }
117+
showTooltip={ true }
118+
isBusy={ isDeleting }
119+
label={ deleteAction.label }
120+
iconSize={ 24 }
121+
icon={ deleteAction.icon }
122+
size="compact"
123+
></Button>
124+
</>
125+
);
126+
127+
default: // 'publish' (inbox) or any other status
128+
return (
129+
<>
130+
<Button
131+
variant="tertiary"
132+
onClick={ handleMarkAsSpam }
133+
isBusy={ isMarkingAsSpam }
134+
showTooltip={ true }
135+
label={ markAsSpamAction.label }
136+
iconSize={ 24 }
137+
icon={ markAsSpamAction.icon }
138+
size="compact"
139+
></Button>
140+
<Button
141+
variant="tertiary"
142+
onClick={ handleMoveToTrash }
143+
isBusy={ isMovingToTrash }
144+
showTooltip={ true }
145+
label={ moveToTrashAction.label }
146+
iconSize={ 24 }
147+
icon={ moveToTrashAction.icon }
148+
size="compact"
149+
></Button>
150+
</>
151+
);
152+
}
153+
};
154+
155+
export default ResponseActions;
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/**
2+
* External dependencies
3+
*/
4+
import { Button } from '@wordpress/components';
5+
import { __ } from '@wordpress/i18n';
6+
import { close, chevronLeft, chevronRight } from '@wordpress/icons';
7+
8+
type ResponseNavigationProps = {
9+
hasNext: boolean;
10+
hasPrevious: boolean;
11+
onClose: ( () => void ) | null;
12+
onNext: () => void;
13+
onPrevious: () => void;
14+
};
15+
16+
const ResponseNavigation = ( {
17+
hasNext,
18+
hasPrevious,
19+
onClose,
20+
onNext,
21+
onPrevious,
22+
}: ResponseNavigationProps ): JSX.Element => {
23+
return (
24+
<>
25+
{ onPrevious && (
26+
<Button
27+
accessibleWhenDisabled={ true }
28+
disabled={ ! hasPrevious }
29+
icon={ chevronLeft }
30+
label={ __( 'Previous', 'jetpack-forms' ) }
31+
onClick={ onPrevious }
32+
showTooltip={ true }
33+
size="compact"
34+
variant="tertiary"
35+
></Button>
36+
) }
37+
{ onNext && (
38+
<Button
39+
accessibleWhenDisabled={ true }
40+
disabled={ ! hasNext }
41+
icon={ chevronRight }
42+
label={ __( 'Next', 'jetpack-forms' ) }
43+
onClick={ onNext }
44+
showTooltip={ true }
45+
size="compact"
46+
variant="tertiary"
47+
></Button>
48+
) }
49+
{ onClose && (
50+
<Button
51+
icon={ close }
52+
label={ __( 'Close', 'jetpack-forms' ) }
53+
onClick={ onClose }
54+
showTooltip={ true }
55+
size="compact"
56+
variant="tertiary"
57+
></Button>
58+
) }
59+
</>
60+
);
61+
};
62+
63+
export default ResponseNavigation;

projects/packages/forms/src/dashboard/inbox/dataviews/index.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import { useSearchParams } from 'react-router';
2020
* Internal dependencies
2121
*/
2222
import InboxStatusToggle from '../../components/inbox-status-toggle';
23+
import ResponseActions from '../../components/response-actions';
24+
import ResponseNavigation from '../../components/response-navigation';
2325
import useInboxData from '../../hooks/use-inbox-data';
2426
import EmptyResponses from '../empty-responses';
2527
import InboxResponse from '../response';
@@ -450,6 +452,18 @@ const SingleResponse = ( {
450452
title={ __( 'Response', 'jetpack-forms' ) }
451453
size="medium"
452454
onRequestClose={ onRequestClose }
455+
headerActions={
456+
<>
457+
<ResponseActions response={ sidePanelItem } onActionComplete={ handleActionComplete } />
458+
<ResponseNavigation
459+
hasNext={ hasNext }
460+
hasPrevious={ hasPrevious }
461+
onClose={ null }
462+
onNext={ handleNext }
463+
onPrevious={ handlePrevious }
464+
/>
465+
</>
466+
}
453467
>
454468
{ contents }
455469
</Modal>

0 commit comments

Comments
 (0)