Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: changed

Forms: Move integrations from tab to button and display in modal
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,22 @@ import { __ } from '@wordpress/i18n';
*/
import IntegrationsList from './integrations-list';
import './style.scss';
/**
* Types
*/
import type { Integration } from '../../../../types';

type BlockAttributes = Record< string, unknown >;

type IntegrationsModalProps = {
isOpen: boolean;
onClose: () => void;
attributes?: BlockAttributes;
setAttributes?: ( attributes: BlockAttributes ) => void;
integrationsData: Integration[];
refreshIntegrations: () => Promise< void >;
context?: 'block-editor' | 'dashboard';
};

const IntegrationsModal = ( {
isOpen,
Expand All @@ -16,7 +32,8 @@ const IntegrationsModal = ( {
setAttributes,
integrationsData,
refreshIntegrations,
} ) => {
context = 'block-editor',
}: IntegrationsModalProps ) => {
if ( ! isOpen ) {
return null;
}
Expand All @@ -32,7 +49,7 @@ const IntegrationsModal = ( {
<IntegrationsList
integrations={ integrationsData }
refreshIntegrations={ refreshIntegrations }
context="block-editor"
context={ context }
attributes={ attributes }
setAttributes={ setAttributes }
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,15 @@ interface ExpandedCardsState {
const IntegrationsList = ( {
integrations = [],
refreshIntegrations,
context,
handlers,
attributes,
setAttributes,
}: IntegrationsListProps ) => {
const items = useIntegrationCardsData( {
integrations,
refreshIntegrations,
context: 'block-editor',
context,
handlers,
attributes,
setAttributes,
Expand All @@ -41,18 +42,21 @@ const IntegrationsList = ( {
const [ expandedCards, setExpandedCards ] =
useState< ExpandedCardsState >( initialCardsExpandedState );

const toggleCard = useCallback( ( id: string ) => {
setExpandedCards( prev => {
const isExpanding = ! prev[ id ];
if ( isExpanding ) {
jetpackAnalytics.tracks.recordEvent( 'jetpack_forms_integrations_card_expand', {
card: id,
origin: 'block-editor',
} );
}
return { ...prev, [ id ]: isExpanding };
} );
}, [] );
const toggleCard = useCallback(
( id: string ) => {
setExpandedCards( prev => {
const isExpanding = ! prev[ id ];
if ( isExpanding ) {
jetpackAnalytics.tracks.recordEvent( 'jetpack_forms_integrations_card_expand', {
card: id,
origin: context,
} );
}
return { ...prev, [ id ]: isExpanding };
} );
},
[ context ]
);

return (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import useCreateForm from '../../hooks/use-create-form';
type CreateFormButtonProps = {
label?: string;
showPatterns?: boolean;
variant?: 'primary' | 'secondary';
};

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

Expand All @@ -46,7 +49,7 @@ export default function CreateFormButton( {
return (
<Button
__next40pxDefaultSize
variant="primary"
variant={ variant }
onClick={ onButtonClickHandler }
icon={ plus }
className="create-form-button"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* External dependencies
*/
import jetpackAnalytics from '@automattic/jetpack-analytics';
import { Button } from '@wordpress/components';
import { useCallback } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { useNavigate } from 'react-router';

/**
* Renders a button to navigate to the integrations page.
*
* @return {JSX.Element} The button to open integrations.
*/
export default function IntegrationsButton(): JSX.Element {
const navigate = useNavigate();

const onButtonClickHandler = useCallback( () => {
jetpackAnalytics.tracks.recordEvent( 'jetpack_forms_integrations_button_click', {
origin: 'dashboard',
} );
navigate( '/integrations' );
}, [ navigate ] );

return (
<Button __next40pxDefaultSize variant="secondary" onClick={ onButtonClickHandler }>
{ __( 'Integrations', 'jetpack-forms' ) }
</Button>
);
}
93 changes: 19 additions & 74 deletions projects/packages/forms/src/dashboard/components/layout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,28 @@
import jetpackAnalytics from '@automattic/jetpack-analytics';
import { useBreakpointMatch, JetpackLogo } from '@automattic/jetpack-components';
import { NavigableRegion, Page } from '@wordpress/admin-ui';
import { TabPanel } from '@wordpress/components';
import { useSelect } from '@wordpress/data';
import { useCallback, useEffect, useMemo } from '@wordpress/element';
import { useEffect } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { Outlet, useLocation, useNavigate } from 'react-router';
import { Outlet, useLocation } from 'react-router';
/**
* Internal dependencies
*/
import useConfigValue from '../../../hooks/use-config-value';
import EmptySpamButton from '../../components/empty-spam-button';
import EmptyTrashButton from '../../components/empty-trash-button';
import ExportResponsesButton from '../../inbox/export-responses';
import Integrations from '../../integrations';
import { store as dashboardStore } from '../../store';
import ActionsDropdownMenu from '../actions-dropdown-menu';
import CreateFormButton from '../create-form-button';
import IntegrationsButton from '../integrations-button';

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

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

const isResponsesTrashView = currentStatus.includes( 'trash' );
const isResponsesSpamView = currentStatus.includes( 'spam' );
const isIntegrationsOpen = location.pathname === '/integrations';

useEffect( () => {
jetpackAnalytics.tracks.recordEvent( 'jetpack_forms_dashboard_page_view', {
viewport: isSm ? 'mobile' : 'desktop',
} );
}, [ isSm ] );

const tabs = useMemo(
() => [
{
name: 'responses',
title: __( 'Responses', 'jetpack-forms' ),
},
...( enableIntegrationsTab
? [ { name: 'integrations', title: __( 'Integrations', 'jetpack-forms' ) } ]
: [] ),
],
[ enableIntegrationsTab ]
);

const getCurrentTab = useCallback( () => {
const path = location.pathname.split( '/' )[ 1 ];
const validTabNames = tabs.map( tab => tab.name );

if ( validTabNames.includes( path ) ) {
return path;
}

return 'responses';
}, [ location.pathname, tabs ] );

const isResponsesTab = getCurrentTab() === 'responses';

const handleTabSelect = useCallback(
( tabName: string ) => {
if ( ! tabName ) {
tabName = 'responses';
}

const currentTab = getCurrentTab();

if ( currentTab !== tabName ) {
jetpackAnalytics.tracks.recordEvent( 'jetpack_forms_dashboard_tab_change', {
tab: tabName,
viewport: isSm ? 'mobile' : 'desktop',
previous_tab: currentTab,
} );
}

navigate( {
pathname: `/${ tabName }`,
search: tabName === 'responses' ? location.search : '',
} );
},
[ navigate, location.search, isSm, getCurrentTab ]
);

const headerActions = isSm ? (
<>
{ isResponsesTab && isResponsesTrashView && <EmptyTrashButton /> }
{ isResponsesTab && isResponsesSpamView && <EmptySpamButton /> }
<ActionsDropdownMenu exportData={ { show: isResponsesTab } } />
{ isResponsesTrashView && <EmptyTrashButton /> }
{ isResponsesSpamView && <EmptySpamButton /> }
<ActionsDropdownMenu exportData={ { show: true } } />
</>
) : (
<div className="jp-forms__layout-header-actions">
{ isResponsesTab && <ExportResponsesButton /> }
{ isResponsesTab && isResponsesTrashView && <EmptyTrashButton /> }
{ isResponsesTab && isResponsesSpamView && <EmptySpamButton /> }
<>
{ isResponsesTrashView && <EmptyTrashButton /> }
{ isResponsesSpamView && <EmptySpamButton /> }
{ ! isResponsesTrashView && ! isResponsesSpamView && (
<CreateFormButton label={ __( 'Create form', 'jetpack-forms' ) } />
<>
{ enableIntegrationsTab && <IntegrationsButton /> }
<CreateFormButton label={ __( 'Create form', 'jetpack-forms' ) } />
</>
) }
</div>
<ExportResponsesButton />
</>
);

return (
Expand All @@ -128,18 +82,9 @@ const Layout = () => {
className="admin-ui-page__content"
ariaLabel={ __( 'Forms dashboard content', 'jetpack-forms' ) }
>
{ ! isLoadingConfig && (
<TabPanel
className="jp-forms__dashboard-tabs"
tabs={ tabs }
initialTabName={ getCurrentTab() }
onSelect={ handleTabSelect }
key={ getCurrentTab() }
>
{ () => <Outlet /> }
</TabPanel>
) }
{ ! isLoadingConfig && <Outlet /> }
</NavigableRegion>
{ isIntegrationsOpen && <Integrations /> }
</Page>
);
};
Expand Down
Loading
Loading