Skip to content

Commit b2d9287

Browse files
lezamaedanzer
andauthored
Forms: Integrations to CTA + Modal (#45662)
--------- Co-authored-by: Erick Danzer <[email protected]>
1 parent 758e77e commit b2d9287

File tree

19 files changed

+132
-985
lines changed

19 files changed

+132
-985
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Significance: minor
2+
Type: changed
3+
4+
Forms: Move integrations from tab to button and display in modal

projects/packages/forms/src/blocks/contact-form/components/jetpack-integrations-modal/index.tsx

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,22 @@ import { __ } from '@wordpress/i18n';
88
*/
99
import IntegrationsList from './integrations-list';
1010
import './style.scss';
11+
/**
12+
* Types
13+
*/
14+
import type { Integration } from '../../../../types';
15+
16+
type BlockAttributes = Record< string, unknown >;
17+
18+
type IntegrationsModalProps = {
19+
isOpen: boolean;
20+
onClose: () => void;
21+
attributes?: BlockAttributes;
22+
setAttributes?: ( attributes: BlockAttributes ) => void;
23+
integrationsData: Integration[];
24+
refreshIntegrations: () => Promise< void >;
25+
context?: 'block-editor' | 'dashboard';
26+
};
1127

1228
const IntegrationsModal = ( {
1329
isOpen,
@@ -16,7 +32,8 @@ const IntegrationsModal = ( {
1632
setAttributes,
1733
integrationsData,
1834
refreshIntegrations,
19-
} ) => {
35+
context = 'block-editor',
36+
}: IntegrationsModalProps ) => {
2037
if ( ! isOpen ) {
2138
return null;
2239
}
@@ -32,7 +49,7 @@ const IntegrationsModal = ( {
3249
<IntegrationsList
3350
integrations={ integrationsData }
3451
refreshIntegrations={ refreshIntegrations }
35-
context="block-editor"
52+
context={ context }
3653
attributes={ attributes }
3754
setAttributes={ setAttributes }
3855
/>

projects/packages/forms/src/blocks/contact-form/components/jetpack-integrations-modal/integrations-list.tsx

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,15 @@ interface ExpandedCardsState {
1717
const IntegrationsList = ( {
1818
integrations = [],
1919
refreshIntegrations,
20+
context,
2021
handlers,
2122
attributes,
2223
setAttributes,
2324
}: IntegrationsListProps ) => {
2425
const items = useIntegrationCardsData( {
2526
integrations,
2627
refreshIntegrations,
27-
context: 'block-editor',
28+
context,
2829
handlers,
2930
attributes,
3031
setAttributes,
@@ -41,18 +42,21 @@ const IntegrationsList = ( {
4142
const [ expandedCards, setExpandedCards ] =
4243
useState< ExpandedCardsState >( initialCardsExpandedState );
4344

44-
const toggleCard = useCallback( ( id: string ) => {
45-
setExpandedCards( prev => {
46-
const isExpanding = ! prev[ id ];
47-
if ( isExpanding ) {
48-
jetpackAnalytics.tracks.recordEvent( 'jetpack_forms_integrations_card_expand', {
49-
card: id,
50-
origin: 'block-editor',
51-
} );
52-
}
53-
return { ...prev, [ id ]: isExpanding };
54-
} );
55-
}, [] );
45+
const toggleCard = useCallback(
46+
( id: string ) => {
47+
setExpandedCards( prev => {
48+
const isExpanding = ! prev[ id ];
49+
if ( isExpanding ) {
50+
jetpackAnalytics.tracks.recordEvent( 'jetpack_forms_integrations_card_expand', {
51+
card: id,
52+
origin: context,
53+
} );
54+
}
55+
return { ...prev, [ id ]: isExpanding };
56+
} );
57+
},
58+
[ context ]
59+
);
5660

5761
return (
5862
<>

projects/packages/forms/src/dashboard/components/create-form-button/index.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import useCreateForm from '../../hooks/use-create-form';
1414
type CreateFormButtonProps = {
1515
label?: string;
1616
showPatterns?: boolean;
17+
variant?: 'primary' | 'secondary';
1718
};
1819

1920
/**
@@ -22,11 +23,13 @@ type CreateFormButtonProps = {
2223
* @param {object} props - The component props.
2324
* @param {string} props.label - The label for the button.
2425
* @param {boolean} props.showPatterns - Whether to show the patterns on the editor immediately.
26+
* @param {string} props.variant - The button variant (primary or secondary).
2527
* @return {JSX.Element} The button to create a new form.
2628
*/
2729
export default function CreateFormButton( {
2830
label = __( 'Create a free form', 'jetpack-forms' ),
2931
showPatterns = false,
32+
variant = 'secondary',
3033
}: CreateFormButtonProps ): JSX.Element {
3134
const { openNewForm } = useCreateForm();
3235

@@ -46,7 +49,7 @@ export default function CreateFormButton( {
4649
return (
4750
<Button
4851
__next40pxDefaultSize
49-
variant="primary"
52+
variant={ variant }
5053
onClick={ onButtonClickHandler }
5154
icon={ plus }
5255
className="create-form-button"
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/**
2+
* External dependencies
3+
*/
4+
import jetpackAnalytics from '@automattic/jetpack-analytics';
5+
import { Button } from '@wordpress/components';
6+
import { useCallback } from '@wordpress/element';
7+
import { __ } from '@wordpress/i18n';
8+
import { useNavigate } from 'react-router';
9+
10+
/**
11+
* Renders a button to navigate to the integrations page.
12+
*
13+
* @return {JSX.Element} The button to open integrations.
14+
*/
15+
export default function IntegrationsButton(): JSX.Element {
16+
const navigate = useNavigate();
17+
18+
const onButtonClickHandler = useCallback( () => {
19+
jetpackAnalytics.tracks.recordEvent( 'jetpack_forms_integrations_button_click', {
20+
origin: 'dashboard',
21+
} );
22+
navigate( '/integrations' );
23+
}, [ navigate ] );
24+
25+
return (
26+
<Button __next40pxDefaultSize variant="secondary" onClick={ onButtonClickHandler }>
27+
{ __( 'Integrations', 'jetpack-forms' ) }
28+
</Button>
29+
);
30+
}

projects/packages/forms/src/dashboard/components/layout/index.tsx

Lines changed: 19 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,28 @@
44
import jetpackAnalytics from '@automattic/jetpack-analytics';
55
import { useBreakpointMatch, JetpackLogo } from '@automattic/jetpack-components';
66
import { NavigableRegion, Page } from '@wordpress/admin-ui';
7-
import { TabPanel } from '@wordpress/components';
87
import { useSelect } from '@wordpress/data';
9-
import { useCallback, useEffect, useMemo } from '@wordpress/element';
8+
import { useEffect } from '@wordpress/element';
109
import { __ } from '@wordpress/i18n';
11-
import { Outlet, useLocation, useNavigate } from 'react-router';
10+
import { Outlet, useLocation } from 'react-router';
1211
/**
1312
* Internal dependencies
1413
*/
1514
import useConfigValue from '../../../hooks/use-config-value';
1615
import EmptySpamButton from '../../components/empty-spam-button';
1716
import EmptyTrashButton from '../../components/empty-trash-button';
1817
import ExportResponsesButton from '../../inbox/export-responses';
18+
import Integrations from '../../integrations';
1919
import { store as dashboardStore } from '../../store';
2020
import ActionsDropdownMenu from '../actions-dropdown-menu';
2121
import CreateFormButton from '../create-form-button';
22+
import IntegrationsButton from '../integrations-button';
2223

2324
import './style.scss';
2425
// eslint-disable-next-line import/no-unresolved -- aliased to the package's built asset in webpack config.
2526
import '@wordpress/admin-ui/build-style/style.css';
2627
const Layout = () => {
2728
const location = useLocation();
28-
const navigate = useNavigate();
2929
const [ isSm ] = useBreakpointMatch( 'sm' );
3030

3131
const enableIntegrationsTab = useConfigValue( 'isIntegrationsEnabled' );
@@ -40,78 +40,32 @@ const Layout = () => {
4040

4141
const isResponsesTrashView = currentStatus.includes( 'trash' );
4242
const isResponsesSpamView = currentStatus.includes( 'spam' );
43+
const isIntegrationsOpen = location.pathname === '/integrations';
4344

4445
useEffect( () => {
4546
jetpackAnalytics.tracks.recordEvent( 'jetpack_forms_dashboard_page_view', {
4647
viewport: isSm ? 'mobile' : 'desktop',
4748
} );
4849
}, [ isSm ] );
4950

50-
const tabs = useMemo(
51-
() => [
52-
{
53-
name: 'responses',
54-
title: __( 'Responses', 'jetpack-forms' ),
55-
},
56-
...( enableIntegrationsTab
57-
? [ { name: 'integrations', title: __( 'Integrations', 'jetpack-forms' ) } ]
58-
: [] ),
59-
],
60-
[ enableIntegrationsTab ]
61-
);
62-
63-
const getCurrentTab = useCallback( () => {
64-
const path = location.pathname.split( '/' )[ 1 ];
65-
const validTabNames = tabs.map( tab => tab.name );
66-
67-
if ( validTabNames.includes( path ) ) {
68-
return path;
69-
}
70-
71-
return 'responses';
72-
}, [ location.pathname, tabs ] );
73-
74-
const isResponsesTab = getCurrentTab() === 'responses';
75-
76-
const handleTabSelect = useCallback(
77-
( tabName: string ) => {
78-
if ( ! tabName ) {
79-
tabName = 'responses';
80-
}
81-
82-
const currentTab = getCurrentTab();
83-
84-
if ( currentTab !== tabName ) {
85-
jetpackAnalytics.tracks.recordEvent( 'jetpack_forms_dashboard_tab_change', {
86-
tab: tabName,
87-
viewport: isSm ? 'mobile' : 'desktop',
88-
previous_tab: currentTab,
89-
} );
90-
}
91-
92-
navigate( {
93-
pathname: `/${ tabName }`,
94-
search: tabName === 'responses' ? location.search : '',
95-
} );
96-
},
97-
[ navigate, location.search, isSm, getCurrentTab ]
98-
);
99-
10051
const headerActions = isSm ? (
10152
<>
102-
{ isResponsesTab && isResponsesTrashView && <EmptyTrashButton /> }
103-
{ isResponsesTab && isResponsesSpamView && <EmptySpamButton /> }
104-
<ActionsDropdownMenu exportData={ { show: isResponsesTab } } />
53+
{ isResponsesTrashView && <EmptyTrashButton /> }
54+
{ isResponsesSpamView && <EmptySpamButton /> }
55+
<ActionsDropdownMenu exportData={ { show: true } } />
10556
</>
10657
) : (
107-
<div className="jp-forms__layout-header-actions">
108-
{ isResponsesTab && <ExportResponsesButton /> }
109-
{ isResponsesTab && isResponsesTrashView && <EmptyTrashButton /> }
110-
{ isResponsesTab && isResponsesSpamView && <EmptySpamButton /> }
58+
<>
59+
{ isResponsesTrashView && <EmptyTrashButton /> }
60+
{ isResponsesSpamView && <EmptySpamButton /> }
11161
{ ! isResponsesTrashView && ! isResponsesSpamView && (
112-
<CreateFormButton label={ __( 'Create form', 'jetpack-forms' ) } />
62+
<>
63+
{ enableIntegrationsTab && <IntegrationsButton /> }
64+
<CreateFormButton label={ __( 'Create form', 'jetpack-forms' ) } />
65+
</>
11366
) }
114-
</div>
67+
<ExportResponsesButton />
68+
</>
11569
);
11670

11771
return (
@@ -128,18 +82,9 @@ const Layout = () => {
12882
className="admin-ui-page__content"
12983
ariaLabel={ __( 'Forms dashboard content', 'jetpack-forms' ) }
13084
>
131-
{ ! isLoadingConfig && (
132-
<TabPanel
133-
className="jp-forms__dashboard-tabs"
134-
tabs={ tabs }
135-
initialTabName={ getCurrentTab() }
136-
onSelect={ handleTabSelect }
137-
key={ getCurrentTab() }
138-
>
139-
{ () => <Outlet /> }
140-
</TabPanel>
141-
) }
85+
{ ! isLoadingConfig && <Outlet /> }
14286
</NavigableRegion>
87+
{ isIntegrationsOpen && <Integrations /> }
14388
</Page>
14489
);
14590
};

0 commit comments

Comments
 (0)