Skip to content

Commit a1019a1

Browse files
authored
Forms: Add useConfigValue hook and start using it in the forms dashboard (#45472)
* Forms: Add new config hook * Add tests * Update to useConfigValue instead of useFormsConfig and config * Remove the on page config for the dashboard * changelog * simply the resolver * Update the readme with example to add a new config * update code to be more readable * Add unknown error constant * Update getConfig resolver * Update the includes to be at the right spot * Add form response type * fix lint error * remove comment
1 parent 88739d9 commit a1019a1

File tree

27 files changed

+1293
-100
lines changed

27 files changed

+1293
-100
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Significance: patch
2+
Type: changed
3+
4+
Forms: add new useConfigValue hook and start using it on the dashboard

projects/packages/forms/src/blocks/contact-form/components/jetpack-integrations-modal/integration-card/plugin-action-button.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { __ } from '@wordpress/i18n';
77
/**
88
* Internal dependencies
99
*/
10-
import useFormsConfig from '../../../../../hooks/use-forms-config';
10+
import useConfigValue from '../../../../../hooks/use-config-value';
1111
import { usePluginInstallation } from '../hooks/use-plugin-installation';
1212

1313
type PluginActionButtonProps = {
@@ -34,9 +34,9 @@ const PluginActionButton = ( {
3434
trackEventName
3535
);
3636

37-
const config = useFormsConfig();
38-
const canUserInstallPlugins = Boolean( config?.canInstallPlugins );
39-
const canUserActivatePlugins = Boolean( config?.canActivatePlugins );
37+
// Permissions from consolidated Forms config (shared across editor and dashboard)
38+
const canUserInstallPlugins = useConfigValue( 'canInstallPlugins' );
39+
const canUserActivatePlugins = useConfigValue( 'canActivatePlugins' );
4040

4141
const canPerformAction = isInstalled ? canUserActivatePlugins : canUserInstallPlugins;
4242
const [ isReconcilingStatus, setIsReconcilingStatus ] = useState( false );

projects/packages/forms/src/blocks/contact-form/edit.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import clsx from 'clsx';
3333
/*
3434
* Internal dependencies
3535
*/
36-
import useFormsConfig from '../../hooks/use-forms-config';
36+
import useConfigValue from '../../hooks/use-config-value';
3737
import { store as singleStepStore } from '../../store/form-step-preview';
3838
import {
3939
PREVIOUS_BUTTON_TEMPLATE,
@@ -168,8 +168,7 @@ function JetpackContactFormEdit( {
168168
disableSummary,
169169
notificationRecipients,
170170
} = attributes;
171-
const formsConfig = useFormsConfig();
172-
const showFormIntegrations = Boolean( formsConfig?.isIntegrationsEnabled );
171+
const showFormIntegrations = useConfigValue( 'isIntegrationsEnabled' );
173172
const instanceId = useInstanceId( JetpackContactFormEdit );
174173

175174
// Backward compatibility for the deprecated customThankyou attribute.

projects/packages/forms/src/dashboard/about/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ import { __ } from '@wordpress/i18n';
99
/**
1010
* Internal dependencies
1111
*/
12+
import useConfigValue from '../../hooks/use-config-value';
1213
import AkismetIcon from '../../icons/akismet';
1314
import CreativeMailIcon from '../../icons/creative-mail';
1415
import GoogleSheetsIcon from '../../icons/google-sheets';
1516
import SalesforceIcon from '../../icons/salesforce';
1617
import CreateFormButton from '../components/create-form-button';
1718
import Details from '../components/details';
18-
import { config } from '../index';
1919
import PatternCard from './pattern-card';
2020
import CheckSVG from './svg/check-svg';
2121
import CloseSVG from './svg/close-svg';
@@ -32,7 +32,7 @@ import './style.scss';
3232
import type { Pattern } from '../../types';
3333

3434
const About = () => {
35-
const ASSETS_URL = useMemo( () => config( 'pluginAssetsURL' ), [] );
35+
const ASSETS_URL = useConfigValue( 'pluginAssetsURL' ); // Ensure config is loaded.
3636

3737
const patterns: Pattern[] = useMemo(
3838
() => [

projects/packages/forms/src/dashboard/class-dashboard.php

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@
1111
use Automattic\Jetpack\Assets;
1212
use Automattic\Jetpack\Connection\Initial_State as Connection_Initial_State;
1313
use Automattic\Jetpack\Forms\ContactForm\Contact_Form_Plugin;
14-
use Automattic\Jetpack\Forms\Jetpack_Forms;
15-
use Automattic\Jetpack\Redirect;
16-
use Automattic\Jetpack\Status;
1714
use Automattic\Jetpack\Tracking;
1815

1916
if ( ! defined( 'ABSPATH' ) ) {
@@ -151,29 +148,8 @@ public function add_new_admin_submenu() {
151148
* Render the dashboard.
152149
*/
153150
public function render_dashboard() {
154-
if ( ! class_exists( 'Jetpack_AI_Helper' ) ) {
155-
require_once JETPACK__PLUGIN_DIR . '_inc/lib/class-jetpack-ai-helper.php';
156-
}
157-
158-
$ai_feature = \Jetpack_AI_Helper::get_ai_assistance_feature();
159-
$has_ai = ! is_wp_error( $ai_feature ) ? $ai_feature['has-feature'] : false;
160-
161-
$config = array(
162-
'blogId' => get_current_blog_id(),
163-
'exportNonce' => wp_create_nonce( 'feedback_export' ),
164-
'newFormNonce' => wp_create_nonce( 'create_new_form' ),
165-
'gdriveConnectSupportURL' => esc_url( Redirect::get_url( 'jetpack-support-contact-form-export' ) ),
166-
'checkForSpamNonce' => wp_create_nonce( 'grunion_recheck_queue' ),
167-
'pluginAssetsURL' => Jetpack_Forms::assets_url(),
168-
'siteURL' => ( new Status() )->get_site_suffix(),
169-
'hasFeedback' => $this->has_feedback(),
170-
'hasAI' => $has_ai,
171-
'dashboardURL' => self::get_forms_admin_url(),
172-
'isMailpoetEnabled' => Jetpack_Forms::is_mailpoet_enabled(),
173-
);
174-
175151
?>
176-
<div id="jp-forms-dashboard" data-config="<?php echo esc_attr( wp_json_encode( $config, JSON_FORCE_OBJECT ) ); ?>"></div>
152+
<div id="jp-forms-dashboard"></div>
177153
<?php
178154
}
179155

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

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,10 @@ import { Outlet, useLocation, useNavigate } from 'react-router';
1111
/**
1212
* Internal dependencies
1313
*/
14-
import useFormsConfig from '../../../hooks/use-forms-config';
14+
import useConfigValue from '../../../hooks/use-config-value';
1515
import EmptySpamButton from '../../components/empty-spam-button';
1616
import EmptyTrashButton from '../../components/empty-trash-button';
1717
import ExportResponsesButton from '../../inbox/export-responses';
18-
import { config } from '../../index';
1918
import { store as dashboardStore } from '../../store';
2019
import ActionsDropdownMenu from '../actions-dropdown-menu';
2120
import CreateFormButton from '../create-form-button';
@@ -27,9 +26,10 @@ const Layout = () => {
2726
const location = useLocation();
2827
const navigate = useNavigate();
2928
const [ isSm ] = useBreakpointMatch( 'sm' );
30-
const formsConfig = useFormsConfig();
3129

32-
const enableIntegrationsTab = Boolean( formsConfig?.isIntegrationsEnabled );
30+
const enableIntegrationsTab = useConfigValue( 'isIntegrationsEnabled' );
31+
const hasFeedback = useConfigValue( 'hasFeedback' );
32+
const isLoadingConfig = enableIntegrationsTab === undefined;
3333

3434
const { currentStatus } = useSelect(
3535
select => ( {
@@ -72,15 +72,15 @@ const Layout = () => {
7272
return path;
7373
}
7474

75-
return config( 'hasFeedback' ) ? 'responses' : 'about';
76-
}, [ location.pathname, tabs ] );
75+
return hasFeedback ? 'responses' : 'about';
76+
}, [ location.pathname, tabs, hasFeedback ] );
7777

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

8080
const handleTabSelect = useCallback(
8181
( tabName: string ) => {
8282
if ( ! tabName ) {
83-
tabName = config( 'hasFeedback' ) ? 'responses' : 'about';
83+
tabName = hasFeedback ? 'responses' : 'about';
8484
}
8585

8686
const currentTab = getCurrentTab();
@@ -98,7 +98,7 @@ const Layout = () => {
9898
search: tabName === 'responses' ? location.search : '',
9999
} );
100100
},
101-
[ navigate, location.search, isSm, getCurrentTab ]
101+
[ navigate, location.search, isSm, getCurrentTab, hasFeedback ]
102102
);
103103

104104
return (
@@ -124,15 +124,17 @@ const Layout = () => {
124124
</div>
125125
) }
126126
</div>
127-
<TabPanel
128-
className="jp-forms__dashboard-tabs"
129-
tabs={ tabs }
130-
initialTabName={ getCurrentTab() }
131-
onSelect={ handleTabSelect }
132-
key={ getCurrentTab() }
133-
>
134-
{ () => <Outlet /> }
135-
</TabPanel>
127+
{ ! isLoadingConfig && (
128+
<TabPanel
129+
className="jp-forms__dashboard-tabs"
130+
tabs={ tabs }
131+
initialTabName={ getCurrentTab() }
132+
onSelect={ handleTabSelect }
133+
key={ getCurrentTab() }
134+
>
135+
{ () => <Outlet /> }
136+
</TabPanel>
137+
) }
136138
</div>
137139
);
138140
};

projects/packages/forms/src/dashboard/components/response-view/body.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@ import clsx from 'clsx';
2424
/**
2525
* Internal dependencies
2626
*/
27-
import useFormsConfig from '../../../hooks/use-forms-config';
27+
import useConfigValue from '../../../hooks/use-config-value';
28+
import CopyClipboardButton from '../../components/copy-clipboard-button';
29+
import Gravatar from '../../components/gravatar';
2830
import { useMarkAsSpam } from '../../hooks/use-mark-as-spam';
2931
import { getPath, updateMenuCounter, updateMenuCounterOptimistically } from '../../inbox/utils';
30-
import CopyClipboardButton from '../copy-clipboard-button';
31-
import Gravatar from '../gravatar';
3232
import type { FormResponse } from '../../../types';
3333

3434
const getDisplayName = response => {
@@ -203,8 +203,7 @@ const ResponseViewBody = ( {
203203

204204
const { editEntityRecord } = useDispatch( 'core' );
205205

206-
const formsConfig = useFormsConfig();
207-
const emptyTrashDays = formsConfig?.emptyTrashDays ?? 0;
206+
const emptyTrashDays = useConfigValue( 'emptyTrashDays' ) ?? 0;
208207

209208
// When opening a "Mark as spam" link from the email, the ResponseViewBody component is rendered, so we use a hook here to handle it.
210209
const { isConfirmDialogOpen, onConfirmMarkAsSpam, onCancelMarkAsSpam } = useMarkAsSpam(

projects/packages/forms/src/dashboard/hooks/use-create-form.ts

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { useCallback } from '@wordpress/element';
55
/**
66
* Internal dependencies
77
*/
8-
import { config } from '../index';
8+
import useConfigValue from '../../hooks/use-config-value';
99

1010
type ClickHandlerProps = {
1111
formPattern?: string;
@@ -24,30 +24,34 @@ type CreateFormReturn = {
2424
* @return {CreateFormReturn} The createForm and openNewForm functions.
2525
*/
2626
export default function useCreateForm(): CreateFormReturn {
27-
const createForm = useCallback( async ( formPattern: string ) => {
28-
const data = new FormData();
27+
const newFormNonce = useConfigValue( 'newFormNonce' );
28+
const createForm = useCallback(
29+
async ( formPattern: string ) => {
30+
const data = new FormData();
2931

30-
data.append( 'action', 'create_new_form' );
31-
data.append( 'newFormNonce', config( 'newFormNonce' ) );
32+
data.append( 'action', 'create_new_form' );
33+
data.append( 'newFormNonce', newFormNonce );
3234

33-
if ( formPattern ) {
34-
data.append( 'pattern', formPattern );
35-
}
35+
if ( formPattern ) {
36+
data.append( 'pattern', formPattern );
37+
}
3638

37-
const response = await fetch( window.ajaxurl, { method: 'POST', body: data } );
39+
const response = await fetch( window.ajaxurl, { method: 'POST', body: data } );
3840

39-
const {
40-
success,
41-
post_url: postUrl,
42-
data: message,
43-
}: { success?: boolean; data?: string; post_url?: string } = await response.json();
41+
const {
42+
success,
43+
post_url: postUrl,
44+
data: message,
45+
}: { success?: boolean; data?: string; post_url?: string } = await response.json();
4446

45-
if ( success === false ) {
46-
throw new Error( message );
47-
}
47+
if ( success === false ) {
48+
throw new Error( message );
49+
}
4850

49-
return postUrl;
50-
}, [] );
51+
return postUrl;
52+
},
53+
[ newFormNonce ]
54+
);
5155

5256
const openNewForm = useCallback(
5357
async ( { formPattern, showPatterns, analyticsEvent }: ClickHandlerProps ) => {

projects/packages/forms/src/dashboard/hooks/use-export-responses.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { __ } from '@wordpress/i18n';
1111
/**
1212
* Internal dependencies
1313
*/
14-
import { config } from '..';
14+
import useConfigValue from '../../hooks/use-config-value';
1515
import { store as dashboardStore } from '../store';
1616

1717
type ExportHookReturn = {
@@ -78,11 +78,13 @@ export default function useExportResponses(): ExportHookReturn {
7878
return { selected: getSelectedResponsesFromCurrentDataset(), currentQuery: getCurrentQuery() };
7979
}, [] );
8080

81+
const exportNonce = useConfigValue( 'exportNonce' );
82+
8183
const onExport = useCallback(
8284
( action: string, nonceName: string ) => {
8385
const data = new FormData();
8486
data.append( 'action', action );
85-
data.append( nonceName, config( 'exportNonce' ) );
87+
data.append( nonceName, exportNonce );
8688
selected.forEach( ( id: string ) => data.append( 'selected[]', id ) );
8789
data.append( 'post', currentQuery.parent || 'all' );
8890
data.append( 'search', currentQuery.search || '' );
@@ -95,7 +97,7 @@ export default function useExportResponses(): ExportHookReturn {
9597

9698
return fetch( window.ajaxurl, { method: 'POST', body: data } );
9799
},
98-
[ currentQuery, selected ]
100+
[ currentQuery, selected, exportNonce ]
99101
);
100102

101103
useEffect( () => {

projects/packages/forms/src/dashboard/inbox/empty-responses.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {
33
__experimentalVStack as VStack, // eslint-disable-line @wordpress/no-unsafe-wp-apis
44
} from '@wordpress/components';
55
import { __, _n, sprintf } from '@wordpress/i18n';
6-
import useFormsConfig from '../../hooks/use-forms-config';
6+
import useConfigValue from '../../hooks/use-config-value';
77

88
const EmptyWrapper = ( { heading = '', body = '' } ) => (
99
<VStack alignment="center" spacing="2">
@@ -22,8 +22,7 @@ type EmptyResponsesProps = {
2222
};
2323

2424
const EmptyResponses = ( { status, isSearch }: EmptyResponsesProps ) => {
25-
const formsConfig = useFormsConfig();
26-
const emptyTrashDays = formsConfig?.emptyTrashDays ?? 0;
25+
const emptyTrashDays = useConfigValue( 'emptyTrashDays' ) ?? 0;
2726

2827
const searchHeading = __( 'No results found', 'jetpack-forms' );
2928
const searchMessage = __(

0 commit comments

Comments
 (0)