diff --git a/projects/packages/forms/changelog/update-integrations-button-modal b/projects/packages/forms/changelog/update-integrations-button-modal new file mode 100644 index 0000000000000..23063b58521af --- /dev/null +++ b/projects/packages/forms/changelog/update-integrations-button-modal @@ -0,0 +1,4 @@ +Significance: minor +Type: changed + +Forms: Move integrations from tab to button and display in modal diff --git a/projects/packages/forms/src/blocks/contact-form/components/jetpack-integrations-modal/index.tsx b/projects/packages/forms/src/blocks/contact-form/components/jetpack-integrations-modal/index.tsx index c4ab9cfdaabf8..dd244446a1905 100644 --- a/projects/packages/forms/src/blocks/contact-form/components/jetpack-integrations-modal/index.tsx +++ b/projects/packages/forms/src/blocks/contact-form/components/jetpack-integrations-modal/index.tsx @@ -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, @@ -16,7 +32,8 @@ const IntegrationsModal = ( { setAttributes, integrationsData, refreshIntegrations, -} ) => { + context = 'block-editor', +}: IntegrationsModalProps ) => { if ( ! isOpen ) { return null; } @@ -32,7 +49,7 @@ const IntegrationsModal = ( { diff --git a/projects/packages/forms/src/blocks/contact-form/components/jetpack-integrations-modal/integrations-list.tsx b/projects/packages/forms/src/blocks/contact-form/components/jetpack-integrations-modal/integrations-list.tsx index 0024aa42e0bcc..78089f4eb3f20 100644 --- a/projects/packages/forms/src/blocks/contact-form/components/jetpack-integrations-modal/integrations-list.tsx +++ b/projects/packages/forms/src/blocks/contact-form/components/jetpack-integrations-modal/integrations-list.tsx @@ -17,6 +17,7 @@ interface ExpandedCardsState { const IntegrationsList = ( { integrations = [], refreshIntegrations, + context, handlers, attributes, setAttributes, @@ -24,7 +25,7 @@ const IntegrationsList = ( { const items = useIntegrationCardsData( { integrations, refreshIntegrations, - context: 'block-editor', + context, handlers, attributes, setAttributes, @@ -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 ( <> diff --git a/projects/packages/forms/src/dashboard/components/create-form-button/index.tsx b/projects/packages/forms/src/dashboard/components/create-form-button/index.tsx index 2d5c06a072b0c..0efd5d38a90f3 100644 --- a/projects/packages/forms/src/dashboard/components/create-form-button/index.tsx +++ b/projects/packages/forms/src/dashboard/components/create-form-button/index.tsx @@ -14,6 +14,7 @@ import useCreateForm from '../../hooks/use-create-form'; type CreateFormButtonProps = { label?: string; showPatterns?: boolean; + variant?: 'primary' | 'secondary'; }; /** @@ -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(); @@ -46,7 +49,7 @@ export default function CreateFormButton( { return ( { + jetpackAnalytics.tracks.recordEvent( 'jetpack_forms_integrations_button_click', { + origin: 'dashboard', + } ); + navigate( '/integrations' ); + }, [ navigate ] ); + + return ( + + { __( 'Integrations', 'jetpack-forms' ) } + + ); +} diff --git a/projects/packages/forms/src/dashboard/components/layout/index.tsx b/projects/packages/forms/src/dashboard/components/layout/index.tsx index fee5ae2a5a38e..b1eaa0b096922 100644 --- a/projects/packages/forms/src/dashboard/components/layout/index.tsx +++ b/projects/packages/forms/src/dashboard/components/layout/index.tsx @@ -4,11 +4,10 @@ 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 */ @@ -16,16 +15,17 @@ 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' ); @@ -40,6 +40,7 @@ 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', { @@ -47,71 +48,24 @@ const Layout = () => { } ); }, [ 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 && } - { isResponsesTab && isResponsesSpamView && } - + { isResponsesTrashView && } + { isResponsesSpamView && } + > ) : ( - - { isResponsesTab && } - { isResponsesTab && isResponsesTrashView && } - { isResponsesTab && isResponsesSpamView && } + <> + { isResponsesTrashView && } + { isResponsesSpamView && } { ! isResponsesTrashView && ! isResponsesSpamView && ( - + <> + { enableIntegrationsTab && } + + > ) } - + + > ); return ( @@ -128,18 +82,9 @@ const Layout = () => { className="admin-ui-page__content" ariaLabel={ __( 'Forms dashboard content', 'jetpack-forms' ) } > - { ! isLoadingConfig && ( - - { () => } - - ) } + { ! isLoadingConfig && } + { isIntegrationsOpen && } ); }; diff --git a/projects/packages/forms/src/dashboard/components/layout/style.scss b/projects/packages/forms/src/dashboard/components/layout/style.scss index eb0fdf8034667..b18d6bf8ea40a 100644 --- a/projects/packages/forms/src/dashboard/components/layout/style.scss +++ b/projects/packages/forms/src/dashboard/components/layout/style.scss @@ -24,11 +24,6 @@ body.jetpack_page_jetpack-forms-admin { width: 100%; min-height: calc(100vh - var(--wp-admin--admin-bar--height, 0px)); - .jp-forms__layout-header-actions { - display: flex; - gap: 8px; - } - .jp-forms__layout-header-title { display: flex; align-items: center; @@ -47,72 +42,40 @@ body.jetpack_page_jetpack-forms-admin { } #jp-forms-dashboard .jp-forms__layout { - background: var(--wpds-color-bg-surface-neutral-strong, #f9f9f6); + background: #fff; .admin-ui-page__content { display: flex; flex: 1 1 auto; flex-direction: column; min-height: 0; + background: var(--jp-white); + + // Ensure Outlet renders as flex child that expands + > * { + display: flex; + flex: 1; + flex-direction: column; + } + + .jp-forms__inbox__dataviews__container { + flex-direction: row; + justify-content: unset; + align-items: unset; + } } .admin-ui-page__header { box-sizing: border-box; margin: 0; - padding: 16px 48px 0; + padding: 16px 48px 4px; width: 100%; + background: transparent; @media (max-width: 782px) { padding: 8px 24px 0; } } - .jp-forms__dashboard-tabs { - display: flex; - flex-direction: column; - flex: 1; - - > .components-tab-panel__tabs { - margin: 0; - padding-inline: 32px; - border-bottom: 1px solid var(--jp-gray-5); - - .components-tab-panel__tabs-item { - border-bottom: 2px solid transparent; - font-size: var(--jp-forms-font-size-regular); - font-weight: 400; - height: 40px; - padding: 8px 16px; - - &.is-active { - border-color: var(--jp-green-50); - font-weight: 500; - - &::after { - display: none; - } - } - } - - @media (max-width: 600px) { - top: 0; - } - - @media (max-width: 660px) { - padding: 0 8px; - } - } - - .jp-forms__inbox__dataviews__container { - justify-content: unset; - align-items: unset; - } - - .components-tab-panel__tab-content { - display: flex; - flex: 1; - background: var(--jp-white); - } - } } diff --git a/projects/packages/forms/src/dashboard/inbox/empty-responses.tsx b/projects/packages/forms/src/dashboard/inbox/empty-responses.tsx index 6c212bf7fad4b..2a058b84bcfdf 100644 --- a/projects/packages/forms/src/dashboard/inbox/empty-responses.tsx +++ b/projects/packages/forms/src/dashboard/inbox/empty-responses.tsx @@ -68,7 +68,9 @@ const EmptyResponses = ( { status, isSearch, readStatusFilter }: EmptyResponsesP 'Share your form to start collecting responses. New items will appear here.', 'jetpack-forms' ) } - actions={ } + actions={ + + } /> ); }; diff --git a/projects/packages/forms/src/dashboard/inbox/export-responses/index.tsx b/projects/packages/forms/src/dashboard/inbox/export-responses/index.tsx index e215f4be9786b..6551773a4efff 100644 --- a/projects/packages/forms/src/dashboard/inbox/export-responses/index.tsx +++ b/projects/packages/forms/src/dashboard/inbox/export-responses/index.tsx @@ -28,7 +28,7 @@ const ExportResponsesButton = () => { return ( <> - + { exportLabel } diff --git a/projects/packages/forms/src/dashboard/index.tsx b/projects/packages/forms/src/dashboard/index.tsx index cb08e10799606..080dee4018981 100644 --- a/projects/packages/forms/src/dashboard/index.tsx +++ b/projects/packages/forms/src/dashboard/index.tsx @@ -10,7 +10,6 @@ import { RouterProvider } from 'react-router/dom'; */ import Layout from './components/layout'; import Inbox from './inbox'; -import Integrations from './integrations'; import DashboardNotices from './notices-list'; import './style.scss'; @@ -47,7 +46,7 @@ function initFormsDashboard() { }, { path: 'integrations', - element: , + element: , }, ], }, diff --git a/projects/packages/forms/src/dashboard/integrations/akismet-card.tsx b/projects/packages/forms/src/dashboard/integrations/akismet-card.tsx deleted file mode 100644 index 7e4d6b359ca40..0000000000000 --- a/projects/packages/forms/src/dashboard/integrations/akismet-card.tsx +++ /dev/null @@ -1,119 +0,0 @@ -/** - * External dependencies - */ -import { getRedirectUrl } from '@automattic/jetpack-components'; -import { Button, ExternalLink, __experimentalHStack as HStack } from '@wordpress/components'; // eslint-disable-line @wordpress/no-unsafe-wp-apis -import { createInterpolateElement, useCallback } from '@wordpress/element'; -import { __ } from '@wordpress/i18n'; -import { useNavigate } from 'react-router'; -/** - * Internal dependencies - */ -import IntegrationCard from '../../blocks/contact-form/components/jetpack-integrations-modal/integration-card'; -import AkismetIcon from '../../icons/akismet'; -/** - * Types - */ -import type { SingleIntegrationCardProps, IntegrationCardData } from '../../types'; - -const AkismetDashboardCard = ( { - isExpanded, - onToggle, - data, - refreshStatus, -}: SingleIntegrationCardProps ) => { - const { - isConnected: akismetActiveWithKey = false, - settingsUrl = '', - marketingUrl = '', - } = data || {}; - const navigate = useNavigate(); - - const cardData: IntegrationCardData = { - ...data, - showHeaderToggle: false, // Always off for dashboard - isLoading: ! data || typeof data.isInstalled === 'undefined', - refreshStatus, - trackEventName: 'jetpack_forms_upsell_akismet_click', - notInstalledMessage: createInterpolateElement( - __( - "Add one-click spam protection for your forms with Akismet. Simply install the plugin and you're set.", - 'jetpack-forms' - ), - { - a: , - } - ), - notActivatedMessage: __( - 'Akismet is installed. Just activate the plugin to start blocking spam.', - 'jetpack-forms' - ), - }; - - const handleViewSpamClick = useCallback( () => { - navigate( '/responses?status=spam' ); - }, [ navigate ] ); - - return ( - } - isExpanded={ isExpanded } - onToggle={ onToggle } - cardData={ cardData } - toggleTooltip={ __( 'We keep your forms protected', 'jetpack-forms' ) } - > - { ! akismetActiveWithKey ? ( - - - { createInterpolateElement( - __( - 'Akismet is active. There is one step left. Please add your Akismet key.', - 'jetpack-forms' - ), - { - a: , - } - ) } - - - - { __( 'Add Akismet key', 'jetpack-forms' ) } - - - { __( 'Refresh status', 'jetpack-forms' ) } - - - - ) : ( - - - { __( 'Your forms are automatically protected with Akismet.', 'jetpack-forms' ) } - - - - { __( 'View spam', 'jetpack-forms' ) } - - | - - { __( 'View stats and settings', 'jetpack-forms' ) } - - | - - { __( 'Learn about Akismet', 'jetpack-forms' ) } - - - - ) } - - ); -}; - -export default AkismetDashboardCard; diff --git a/projects/packages/forms/src/dashboard/integrations/google-sheets-card.tsx b/projects/packages/forms/src/dashboard/integrations/google-sheets-card.tsx deleted file mode 100644 index 866a569f14dc6..0000000000000 --- a/projects/packages/forms/src/dashboard/integrations/google-sheets-card.tsx +++ /dev/null @@ -1,148 +0,0 @@ -/** - * External dependencies - */ -import requestExternalAccess from '@automattic/request-external-access'; -import apiFetch from '@wordpress/api-fetch'; -import { Button, __experimentalHStack as HStack } from '@wordpress/components'; // eslint-disable-line @wordpress/no-unsafe-wp-apis -import { useCallback, useEffect, useState } from '@wordpress/element'; -import { __, _x } from '@wordpress/i18n'; -import { useNavigate } from 'react-router'; -/** - * Internal dependencies - */ -import IntegrationCard from '../../blocks/contact-form/components/jetpack-integrations-modal/integration-card'; -import GoogleSheetsIcon from '../../icons/google-sheets'; -/** - * Types - */ -import type { SingleIntegrationCardProps, IntegrationCardData } from '../../types'; - -const GoogleSheetsDashboardCard = ( { - isExpanded, - onToggle, - data, - refreshStatus, -}: SingleIntegrationCardProps ) => { - const isConnected = !! data?.isConnected; - const settingsUrl = data?.settingsUrl; - const navigate = useNavigate(); - const [ isTogglingConnection, setIsTogglingConnection ] = useState( false ); - - useEffect( () => { - setIsTogglingConnection( false ); - }, [ isConnected ] ); - - const cardData: IntegrationCardData = { - ...data, - slug: 'google-sheets', - showHeaderToggle: false, // Always off for dashboard - isLoading: ! data, - refreshStatus, - trackEventName: 'jetpack_forms_upsell_googledrive_click', - isActive: !! data?.isConnected, - }; - - const handleConnectClick = useCallback( () => { - if ( ! settingsUrl ) return; - setIsTogglingConnection( true ); - requestExternalAccess( settingsUrl, ( { keyring_id: keyringId } ) => { - if ( keyringId ) { - refreshStatus(); - } else { - setIsTogglingConnection( false ); - } - } ); - }, [ settingsUrl, refreshStatus ] ); - - const handleViewResponsesClick = useCallback( () => { - navigate( '/responses' ); - }, [ navigate ] ); - - const handleDisconnectClick = useCallback( () => { - setIsTogglingConnection( true ); - apiFetch( { - method: 'DELETE', - path: '/wp/v2/feedback/integrations/google-drive', - } ) - .then( ( response: { deleted: boolean } ) => { - if ( response.deleted ) { - refreshStatus(); - } else { - setIsTogglingConnection( false ); - } - } ) - .catch( () => { - setIsTogglingConnection( false ); - } ); - }, [ refreshStatus ] ); - - return ( - } - isExpanded={ isExpanded } - onToggle={ onToggle } - cardData={ cardData } - > - { ! isConnected ? ( - - - { __( - 'Connect your site to Google Drive to export form responses directly to Google Sheets.', - 'jetpack-forms' - ) } - - - - { isTogglingConnection - ? __( 'Connecting…', 'jetpack-forms' ) - : _x( - 'Connect to Google Drive', - '', // Dummy context to avoid bad minification. See https://github.com/Automattic/jetpack/tree/e3f007ec7ac80715f3d82db33c9ed8098a7b45b4/projects/js-packages/i18n-check-webpack-plugin#conditional-function-call-compaction - 'jetpack-forms' - ) } - - - - ) : ( - - - { __( - 'Google Sheets is connected. You can export your form responses from the form responses page.', - 'jetpack-forms' - ) } - - - - { __( 'View form responses', 'jetpack-forms' ) } - - | - - { isTogglingConnection - ? __( 'Disconnecting…', 'jetpack-forms' ) - : _x( - 'Disconnect Google Drive', - '', // Dummy context to avoid bad minification. See https://github.com/Automattic/jetpack/tree/e3f007ec7ac80715f3d82db33c9ed8098a7b45b4/projects/js-packages/i18n-check-webpack-plugin#conditional-function-call-compaction - 'jetpack-forms' - ) } - - - - ) } - - ); -}; - -export default GoogleSheetsDashboardCard; diff --git a/projects/packages/forms/src/dashboard/integrations/hostinger-reach-card.tsx b/projects/packages/forms/src/dashboard/integrations/hostinger-reach-card.tsx deleted file mode 100644 index 3cb3520936c3d..0000000000000 --- a/projects/packages/forms/src/dashboard/integrations/hostinger-reach-card.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import { Button, ExternalLink, __experimentalHStack as HStack } from '@wordpress/components'; // eslint-disable-line @wordpress/no-unsafe-wp-apis -import { createInterpolateElement } from '@wordpress/element'; -import { __ } from '@wordpress/i18n'; -import IntegrationCard from '../../blocks/contact-form/components/jetpack-integrations-modal/integration-card'; -import HostingerReachIcon from '../../icons/hostinger-reach'; -import type { SingleIntegrationCardProps, IntegrationCardData } from '../../types'; - -const HostingerReachDashboardCard = ( { - isExpanded, - onToggle, - data, - refreshStatus, -}: SingleIntegrationCardProps ) => { - const { isConnected = false, settingsUrl = '', marketingUrl = '' } = data || {}; - - const cardData: IntegrationCardData = { - ...data, - showHeaderToggle: false, - isLoading: ! data || typeof data.isInstalled === 'undefined', - refreshStatus, - trackEventName: 'jetpack_forms_upsell_hostinger_reach_click', - notInstalledMessage: createInterpolateElement( - __( - 'Add powerful email marketing to your forms with Hostinger Reach. Simply install the plugin to start sending emails.', - 'jetpack-forms' - ), - { - a: , - } - ), - notActivatedMessage: __( - 'Hostinger Reach is installed. Just activate the plugin to start sending emails.', - 'jetpack-forms' - ), - }; - - return ( - } - isExpanded={ isExpanded } - onToggle={ onToggle } - cardData={ cardData } - toggleTooltip={ __( 'Grow your audience with Hostinger Reach', 'jetpack-forms' ) } - > - { ! isConnected ? ( - - - { createInterpolateElement( - __( - 'Hostinger Reach is active. There is one step left. Please complete Hostinger Reach setup.', - 'jetpack-forms' - ), - { - a: , - } - ) } - - - - { __( 'Complete Hostinger Reach setup', 'jetpack-forms' ) } - - - { __( 'Refresh status', 'jetpack-forms' ) } - - - - ) : ( - - - { __( 'You can now send marketing emails with Hostinger Reach.', 'jetpack-forms' ) } - - - { __( 'View Hostinger Reach dashboard', 'jetpack-forms' ) } - - - ) } - - ); -}; - -export default HostingerReachDashboardCard; diff --git a/projects/packages/forms/src/dashboard/integrations/index.tsx b/projects/packages/forms/src/dashboard/integrations/index.tsx index 0b5e672bad217..e0ff04f28bc8c 100644 --- a/projects/packages/forms/src/dashboard/integrations/index.tsx +++ b/projects/packages/forms/src/dashboard/integrations/index.tsx @@ -1,21 +1,14 @@ /** * External dependencies */ -import jetpackAnalytics from '@automattic/jetpack-analytics'; import { useSelect, useDispatch } from '@wordpress/data'; -import { __ } from '@wordpress/i18n'; -import { useState, useCallback } from 'react'; +import { useCallback } from '@wordpress/element'; +import { useNavigate } from 'react-router'; /** * Internal dependencies */ +import IntegrationsModal from '../../blocks/contact-form/components/jetpack-integrations-modal'; import { INTEGRATIONS_STORE } from '../../store/integrations'; -import AkismetDashboardCard from './akismet-card'; -import GoogleSheetsDashboardCard from './google-sheets-card'; -import HostingerReachDashboardCard from './hostinger-reach-card'; -import JetpackCRMDashboardCard from './jetpack-crm-card'; -import MailPoetDashboardCard from './mailpoet-card'; -import SalesforceDashboardCard from './salesforce-card'; -import './style.scss'; /** * Types */ @@ -25,6 +18,7 @@ import type { Integration } from '../../types'; const EMPTY_ARRAY: Integration[] = []; const Integrations = () => { + const navigate = useNavigate(); const { integrations } = useSelect( ( select: SelectIntegrations ) => { const store = select( INTEGRATIONS_STORE ); return { @@ -32,123 +26,21 @@ const Integrations = () => { }; }, [] ) as { integrations: Integration[] }; const { refreshIntegrations } = useDispatch( INTEGRATIONS_STORE ) as IntegrationsDispatch; - const [ expandedCards, setExpandedCards ] = useState( { - akismet: false, - googleSheets: false, - crm: false, - salesforce: false, - mailpoet: false, - hostingerReach: false, - } ); - const toggleCard = useCallback( ( cardId: keyof typeof expandedCards ) => { - setExpandedCards( prev => { - const isExpanding = ! prev[ cardId ]; - - if ( isExpanding ) { - jetpackAnalytics.tracks.recordEvent( 'jetpack_forms_integrations_card_expand', { - card: cardId, - origin: 'dashboard', - } ); - } - - return { - ...prev, - [ cardId ]: isExpanding, - }; - } ); - }, [] ); - - const handleToggleAkismet = useCallback( () => toggleCard( 'akismet' ), [ toggleCard ] ); - const handleToggleGoogleSheets = useCallback( - () => toggleCard( 'googleSheets' ), - [ toggleCard ] - ); - const handleToggleCRM = useCallback( () => toggleCard( 'crm' ), [ toggleCard ] ); - const handleToggleSalesforce = useCallback( () => toggleCard( 'salesforce' ), [ toggleCard ] ); - const handleToggleMailPoet = useCallback( () => toggleCard( 'mailpoet' ), [ toggleCard ] ); - const handleToggleHostingerReach = useCallback( - () => toggleCard( 'hostingerReach' ), - [ toggleCard ] - ); - - const findIntegrationById = ( id: string ) => - integrations.find( integration => integration.id === id ); - - // Only supported integrations will be returned from endpoint. - const akismetData = findIntegrationById( 'akismet' ); - const googleDriveData = findIntegrationById( 'google-drive' ); - const crmData = findIntegrationById( 'zero-bs-crm' ); - const mailpoetData = findIntegrationById( 'mailpoet' ); - const salesforceData = findIntegrationById( 'salesforce' ); - const hostingerReachData = findIntegrationById( 'hostinger-reach' ); + const handleClose = useCallback( () => { + navigate( '/responses' ); + }, [ navigate ] ); return ( - - - - - { __( 'Streamline your forms', 'jetpack-forms' ) } - - - { __( - 'Manage integrations for all forms on your site. You can turn them on or off per form in the editor.', - 'jetpack-forms' - ) } - - - - { akismetData && ( - - ) } - { googleDriveData && ( - - ) } - { crmData && ( - - ) } - { mailpoetData && ( - - ) } - { salesforceData && ( - - ) } - { hostingerReachData && ( - - ) } - - - + ); }; diff --git a/projects/packages/forms/src/dashboard/integrations/jetpack-crm-card.tsx b/projects/packages/forms/src/dashboard/integrations/jetpack-crm-card.tsx deleted file mode 100644 index 444d883e4a8c8..0000000000000 --- a/projects/packages/forms/src/dashboard/integrations/jetpack-crm-card.tsx +++ /dev/null @@ -1,148 +0,0 @@ -/** - * External dependencies - */ -import colorStudio from '@automattic/color-studio'; -import { JetpackIcon } from '@automattic/jetpack-components'; -import { Button, ExternalLink } from '@wordpress/components'; -import { createInterpolateElement } from '@wordpress/element'; -import { __ } from '@wordpress/i18n'; -import semver from 'semver'; -/** - * Internal dependencies - */ -import IntegrationCard from '../../blocks/contact-form/components/jetpack-integrations-modal/integration-card'; -/** - * Types - */ -import type { SingleIntegrationCardProps, IntegrationCardData } from '../../types'; - -const COLOR_JETPACK = colorStudio.colors[ 'Jetpack Green 40' ]; - -const JetpackCRMDashboardCard = ( { - isExpanded, - onToggle, - data, - refreshStatus, -}: SingleIntegrationCardProps ) => { - const { settingsUrl = '', marketingUrl = '', version = '', details = {} } = data || {}; - const { hasExtension = false, canActivateExtension = false } = details; - - const crmVersion = semver.coerce( version ); - const isRecentVersion = crmVersion && semver.gte( crmVersion, '4.9.1' ); - - const cardData: IntegrationCardData = { - ...data, - showHeaderToggle: false, // Always off for dashboard - isLoading: ! data || typeof data.isInstalled === 'undefined', - refreshStatus, - trackEventName: 'jetpack_forms_upsell_crm_click', - notInstalledMessage: createInterpolateElement( - __( - 'You can save your form contacts in Jetpack CRM. To get started, please install the plugin.', - 'jetpack-forms' - ), - { - a: , - } - ), - notActivatedMessage: __( - 'Jetpack CRM is installed. To start saving contacts, simply activate the plugin.', - 'jetpack-forms' - ), - }; - - const renderContent = () => { - // Jetpack CRM installed and active, but not recent version - if ( ! isRecentVersion ) { - return ( - - - { __( - 'Please update to the latest version of the Jetpack CRM plugin to integrate your contact form with your CRM.', - 'jetpack-forms' - ) } - - - { __( 'Update Jetpack CRM', 'jetpack-forms' ) } - - - ); - } - - // Jetpack CRM installed, active, and recent, but no extension - if ( ! hasExtension ) { - return ( - - - { createInterpolateElement( - __( - "You can integrate Jetpack CRM by enabling Jetpack CRM's Jetpack Forms extension.", - 'jetpack-forms' - ), - { - a: ( - - ), - } - ) } - - { ! canActivateExtension && ( - - { __( - 'A site administrator must enable the CRM Jetpack Forms extension.', - 'jetpack-forms' - ) } - - ) } - { canActivateExtension && ( - - { __( 'Enable Jetpack Forms extension', 'jetpack-forms' ) } - - ) } - - ); - } - - // All conditions met, show Jetpack CRM connected message - return ( - - { __( 'Jetpack CRM is connected.', 'jetpack-forms' ) } - - { __( 'Open Jetpack CRM settings', 'jetpack-forms' ) } - - - ); - }; - - return ( - } - isExpanded={ isExpanded } - onToggle={ onToggle } - cardData={ cardData } - > - { renderContent() } - - ); -}; - -export default JetpackCRMDashboardCard; diff --git a/projects/packages/forms/src/dashboard/integrations/mailpoet-card.tsx b/projects/packages/forms/src/dashboard/integrations/mailpoet-card.tsx deleted file mode 100644 index 67eefc63e4995..0000000000000 --- a/projects/packages/forms/src/dashboard/integrations/mailpoet-card.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import { Button, ExternalLink, __experimentalHStack as HStack } from '@wordpress/components'; // eslint-disable-line @wordpress/no-unsafe-wp-apis -import { createInterpolateElement } from '@wordpress/element'; -import { __ } from '@wordpress/i18n'; -import IntegrationCard from '../../blocks/contact-form/components/jetpack-integrations-modal/integration-card'; -import MailPoetIcon from '../../icons/mailpoet'; -import type { SingleIntegrationCardProps, IntegrationCardData } from '../../types'; - -const MailPoetDashboardCard = ( { - isExpanded, - onToggle, - data, - refreshStatus, -}: SingleIntegrationCardProps ) => { - const { - isConnected: mailpoetActiveWithKey = false, - settingsUrl = '', - marketingUrl = '', - } = data || {}; - - const cardData: IntegrationCardData = { - ...data, - showHeaderToggle: false, - isLoading: ! data || typeof data.isInstalled === 'undefined', - refreshStatus, - trackEventName: 'jetpack_forms_upsell_mailpoet_click', - notInstalledMessage: createInterpolateElement( - __( - 'Add powerful email marketing to your forms with MailPoet. Simply install the plugin to start sending emails.', - 'jetpack-forms' - ), - { - a: , - } - ), - notActivatedMessage: __( - 'MailPoet is installed. Just activate the plugin to start sending emails.', - 'jetpack-forms' - ), - }; - - return ( - } - isExpanded={ isExpanded } - onToggle={ onToggle } - cardData={ cardData } - toggleTooltip={ __( 'Grow your audience with MailPoet', 'jetpack-forms' ) } - > - { ! mailpoetActiveWithKey ? ( - - - { createInterpolateElement( - __( - 'MailPoet is active. There is one step left. Please complete MailPoet setup.', - 'jetpack-forms' - ), - { - a: , - } - ) } - - - - { __( 'Complete MailPoet setup', 'jetpack-forms' ) } - - - { __( 'Refresh status', 'jetpack-forms' ) } - - - - ) : ( - - - { __( 'You can now send marketing emails with MailPoet.', 'jetpack-forms' ) } - - - { __( 'View MailPoet dashboard', 'jetpack-forms' ) } - - - ) } - - ); -}; - -export default MailPoetDashboardCard; diff --git a/projects/packages/forms/src/dashboard/integrations/salesforce-card.tsx b/projects/packages/forms/src/dashboard/integrations/salesforce-card.tsx deleted file mode 100644 index 0ad7eac55676b..0000000000000 --- a/projects/packages/forms/src/dashboard/integrations/salesforce-card.tsx +++ /dev/null @@ -1,73 +0,0 @@ -/** - * External dependencies - */ -import { Badge } from '@automattic/ui'; -import '@automattic/ui/style.css'; -import { Button } from '@wordpress/components'; -import { useCallback } from '@wordpress/element'; -import { __ } from '@wordpress/i18n'; -/** - * Internal dependencies - */ -import IntegrationCard from '../../blocks/contact-form/components/jetpack-integrations-modal/integration-card'; -import SalesforceIcon from '../../icons/salesforce'; -import useCreateForm from '../hooks/use-create-form'; -/** - * Types - */ -import type { SingleIntegrationCardProps, IntegrationCardData } from '../../types'; - -const SalesforceDashboardCard = ( { - isExpanded, - onToggle, - data, - refreshStatus, -}: SingleIntegrationCardProps ) => { - const { openNewForm } = useCreateForm(); - const handleCreateSalesforceForm = useCallback( () => { - openNewForm( { - formPattern: 'salesforce-lead-form', - analyticsEvent: () => { - if ( window.jetpackAnalytics?.tracks ) { - window.jetpackAnalytics.tracks.recordEvent( 'jetpack_forms_salesforce_lead_form_click' ); - } - }, - } ); - }, [ openNewForm ] ); - const cardData: IntegrationCardData = { - ...data, - showHeaderToggle: false, // Always off for dashboard - isLoading: ! data || typeof data.isInstalled === 'undefined', - refreshStatus, - setupBadge: ( - - { __( 'Configured per form', 'jetpack-forms' ) } - - ), - }; - - return ( - } - isExpanded={ isExpanded } - onToggle={ onToggle } - cardData={ cardData } - > - - - { __( - 'Salesforce connections are managed for each form individually in the block editor.', - 'jetpack-forms' - ) } - - - { __( 'Create Salesforce lead form', 'jetpack-forms' ) } - - - - ); -}; - -export default SalesforceDashboardCard; diff --git a/projects/packages/forms/src/dashboard/integrations/style.scss b/projects/packages/forms/src/dashboard/integrations/style.scss deleted file mode 100644 index daea4232a4938..0000000000000 --- a/projects/packages/forms/src/dashboard/integrations/style.scss +++ /dev/null @@ -1,43 +0,0 @@ -@use "@wordpress/base-styles/colors"; -@use "@wordpress/base-styles/variables"; - -.jp-forms__integrations { - padding: 32px 8px; - margin: 0 auto 24px auto; - width: 720px; - max-width: 98%; - - .jp-forms__integrations-header { - display: flex; - flex-direction: column; - gap: 8px; - margin-bottom: 24px; - - .jp-forms__integrations-header-heading { - color: colors.$gray-900; - font-size: variables.$font-size-2x-large; - line-height: variables.$font-line-height-2x-large; - margin-block: 0; - } - - .jp-forms__integrations-header-description { - color: colors.$gray-700; - max-width: 75ch; /* stylelint-disable-line unit-allowed-list */ - } - } - - .jp-forms__integrations-body { - border: 1px solid colors.$gray-200; - border-radius: 8px; - padding: 12px 24px; - background: colors.$white; - - > div:last-of-type { - border-bottom: none; - } - - @media ( max-width: 782px ) { - padding: 12px 8px; - } - } -} diff --git a/projects/packages/forms/tools/webpack.config.dashboard.js b/projects/packages/forms/tools/webpack.config.dashboard.js index b0464d86721f4..9d8ab9082d229 100644 --- a/projects/packages/forms/tools/webpack.config.dashboard.js +++ b/projects/packages/forms/tools/webpack.config.dashboard.js @@ -113,6 +113,8 @@ module.exports = { // Bundle the package with our assets until WP core exposes wp-admin-ui. '@wordpress/admin-ui': { external: false }, '@wordpress/admin-ui/build-style/style.css': { external: false }, + // Bundle jetpack-connection since it's used by IntegrationsModal + '@automattic/jetpack-connection': { external: false }, }, }, } ),
- { createInterpolateElement( - __( - 'Akismet is active. There is one step left. Please add your Akismet key.', - 'jetpack-forms' - ), - { - a: , - } - ) } -
- { __( 'Your forms are automatically protected with Akismet.', 'jetpack-forms' ) } -
- { __( - 'Connect your site to Google Drive to export form responses directly to Google Sheets.', - 'jetpack-forms' - ) } -
- { __( - 'Google Sheets is connected. You can export your form responses from the form responses page.', - 'jetpack-forms' - ) } -
- { createInterpolateElement( - __( - 'Hostinger Reach is active. There is one step left. Please complete Hostinger Reach setup.', - 'jetpack-forms' - ), - { - a: , - } - ) } -
- { __( 'You can now send marketing emails with Hostinger Reach.', 'jetpack-forms' ) } -
- { __( - 'Please update to the latest version of the Jetpack CRM plugin to integrate your contact form with your CRM.', - 'jetpack-forms' - ) } -
- { createInterpolateElement( - __( - "You can integrate Jetpack CRM by enabling Jetpack CRM's Jetpack Forms extension.", - 'jetpack-forms' - ), - { - a: ( - - ), - } - ) } -
- { __( - 'A site administrator must enable the CRM Jetpack Forms extension.', - 'jetpack-forms' - ) } -
{ __( 'Jetpack CRM is connected.', 'jetpack-forms' ) }
- { createInterpolateElement( - __( - 'MailPoet is active. There is one step left. Please complete MailPoet setup.', - 'jetpack-forms' - ), - { - a: , - } - ) } -
- { __( 'You can now send marketing emails with MailPoet.', 'jetpack-forms' ) } -
- { __( - 'Salesforce connections are managed for each form individually in the block editor.', - 'jetpack-forms' - ) } -