diff --git a/.yarnrc.yml b/.yarnrc.yml index 40e964db22200..eac16f4b03c6c 100644 --- a/.yarnrc.yml +++ b/.yarnrc.yml @@ -111,6 +111,12 @@ logFilters: pattern: "@automattic/global-styles@workspace:packages/global-styles provides react-dom (*) with version 17.0.2, which doesn't satisfy what @wordpress/block-editor and some of its descendants request" - level: discard pattern: "@automattic/global-styles@workspace:packages/global-styles provides react-dom (*) with version 17.0.2, which doesn't satisfy what @wordpress/components and some of its descendants request" + - level: discard + pattern: "@wordpress/data-controls@npm:2.27.0 doesn't provide react (p90380), requested by @wordpress/data" + - level: discard + pattern: "@wordpress/notices@npm:3.27.0 doesn't provide react (pcdad4), requested by @wordpress/data" + - level: discard + pattern: "calypso@workspace:client provides @wordpress/data (pd64ed) with version 7.6.0, which doesn't satisfy what @automattic/subscription-manager requests" nodeLinker: node-modules @@ -123,28 +129,13 @@ packageExtensions: "@signal-noise/stylelint-scales@2.0.3": peerDependencies: postcss: "*" - "@types/wordpress__block-editor@6.0.5": - peerDependencies: - react: "*" - react-dom: "*" - "@types/wordpress__blocks@6.4.12": - peerDependencies: - react: "*" "@types/wordpress__components@14.0.10": peerDependencies: react: "*" - "@types/wordpress__editor@10.0.1": - peerDependencies: - react: "*" - react-dom: "*" - "@types/wordpress__media-utils@0.2.4": - peerDependencies: - react: "*" - react-dom: "*" "@types/wordpress__plugins@3.0.0": peerDependencies: react: "*" - "@wordpress/stylelint-config@20.0.3": + "@wordpress/stylelint-config@21.10.0": peerDependencies: postcss: "*" fake-indexeddb@3.1.7: diff --git a/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/attach-focused-launch.tsx b/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/attach-focused-launch.tsx index 2399bfca882a2..677878d31e109 100644 --- a/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/attach-focused-launch.tsx +++ b/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/attach-focused-launch.tsx @@ -7,6 +7,7 @@ import { inIframe } from '../../block-inserter-modifications/contextual-tips/uti import { IMMEDIATE_LAUNCH_QUERY_ARG } from './constants'; import { LAUNCH_STORE, SITE_STORE } from './stores'; import { openCheckout, redirectToWpcomPath, getCurrentLaunchFlowUrl } from './utils'; +import type { LaunchSelect, SiteSelect } from '@automattic/data-stores'; const registerPlugin = ( name: string, settings: Omit< PluginSettings, 'icon' > ) => // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -17,12 +18,12 @@ registerPlugin( 'a8c-editor-editor-focused-launch', { const currentSiteId = window._currentSiteId; const isSiteLaunched = useSelect( - ( select ) => select( SITE_STORE ).isSiteLaunched( currentSiteId ), + ( select ) => ( select( SITE_STORE ) as SiteSelect ).isSiteLaunched( currentSiteId ), [ currentSiteId ] ); const { isFocusedLaunchOpen, isAnchorFm } = useSelect( - ( select ) => select( LAUNCH_STORE ).getState(), + ( select ) => ( select( LAUNCH_STORE ) as LaunchSelect ).getState(), [] ); diff --git a/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/attach-launch-sidebar.tsx b/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/attach-launch-sidebar.tsx index 39bed3613c419..3a5c45eabfed3 100644 --- a/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/attach-launch-sidebar.tsx +++ b/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/attach-launch-sidebar.tsx @@ -9,6 +9,7 @@ import { FLOW_ID } from './constants'; import LaunchModal from './launch-modal'; import { LAUNCH_STORE } from './stores'; import { openCheckout, redirectToWpcomPath, getCurrentLaunchFlowUrl } from './utils'; +import type { LaunchSelect } from '@automattic/data-stores'; const registerPlugin = ( name: string, settings: Omit< PluginSettings, 'icon' > ) => // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -16,7 +17,10 @@ const registerPlugin = ( name: string, settings: Omit< PluginSettings, 'icon' > registerPlugin( 'a8c-editor-site-launch', { render: function LaunchSidebar() { - const { isSidebarOpen } = useSelect( ( select ) => select( LAUNCH_STORE ).getState() ); + const { isSidebarOpen } = useSelect( + ( select ) => ( select( LAUNCH_STORE ) as LaunchSelect ).getState(), + [] + ); const { closeSidebar, setSidebarFullscreen, unsetSidebarFullscreen } = useDispatch( LAUNCH_STORE ); diff --git a/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/launch-menu/index.tsx b/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/launch-menu/index.tsx index 7e90066dc8e49..2a17f711cfc59 100644 --- a/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/launch-menu/index.tsx +++ b/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/launch-menu/index.tsx @@ -4,6 +4,7 @@ import * as React from 'react'; import { LAUNCH_STORE } from '../stores'; import LaunchMenuItem from './item'; import type { LaunchStepType } from '../../../common/data-stores/launch'; +import type { LaunchSelect } from '@automattic/data-stores'; import './styles.scss'; @@ -16,7 +17,7 @@ const LaunchMenu: React.FunctionComponent< Props > = ( { onMenuItemClick } ) => const { currentStep, LaunchStep, LaunchSequence, isStepCompleted, isFlowCompleted } = useSelect( ( select ) => { - const launchStore = select( LAUNCH_STORE ); + const launchStore: LaunchSelect = select( LAUNCH_STORE ); return { currentStep: launchStore.getCurrentStep(), LaunchStep: launchStore.getLaunchStep(), @@ -24,7 +25,8 @@ const LaunchMenu: React.FunctionComponent< Props > = ( { onMenuItemClick } ) => isStepCompleted: launchStore.isStepCompleted, isFlowCompleted: launchStore.isFlowCompleted(), }; - } + }, + [] ); const LaunchStepMenuItemTitles = { diff --git a/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/launch-modal/index.tsx b/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/launch-modal/index.tsx index 7b6f504bbcf18..38395bea0cca4 100644 --- a/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/launch-modal/index.tsx +++ b/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/launch-modal/index.tsx @@ -10,6 +10,7 @@ import Launch from '../launch'; import LaunchProgress from '../launch-progress'; import LaunchSidebar from '../launch-sidebar'; import { LAUNCH_STORE, SITE_STORE, PLANS_STORE } from '../stores'; +import type { LaunchSelect, PlansSelect } from '@automattic/data-stores'; import './styles.scss'; @@ -21,8 +22,9 @@ interface Props { const LaunchModal: React.FunctionComponent< Props > = ( { onClose, isLaunchImmediately } ) => { const { siteId } = React.useContext( LaunchContext ); - const { step: currentStep, isSidebarFullscreen } = useSelect( ( select ) => - select( LAUNCH_STORE ).getState() + const { step: currentStep, isSidebarFullscreen } = useSelect( + ( select ) => ( select( LAUNCH_STORE ) as LaunchSelect ).getState(), + [] ); const [ isLaunching, setIsLaunching ] = React.useState( false ); const [ isImmediateLaunchStarted, setIsImmediateLaunchStarted ] = React.useState( false ); @@ -32,8 +34,9 @@ const LaunchModal: React.FunctionComponent< Props > = ( { onClose, isLaunchImmed const locale = useLocale(); const { setPlanProductId } = useDispatch( LAUNCH_STORE ); - const defaultFreePlan = useSelect( ( select ) => - select( PLANS_STORE ).getDefaultFreePlan( locale ) + const defaultFreePlan = useSelect( + ( select ) => ( select( PLANS_STORE ) as PlansSelect ).getDefaultFreePlan( locale ), + [ locale ] ); const handleLaunch = React.useCallback( () => { diff --git a/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/launch-progress/index.tsx b/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/launch-progress/index.tsx index 8d820dd398330..ee0c77968c3fd 100644 --- a/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/launch-progress/index.tsx +++ b/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/launch-progress/index.tsx @@ -3,6 +3,7 @@ import { sprintf } from '@wordpress/i18n'; import { useI18n } from '@wordpress/react-i18n'; import * as React from 'react'; import { LAUNCH_STORE } from '../stores'; +import type { LaunchSelect } from '@automattic/data-stores'; import './styles.scss'; @@ -10,12 +11,12 @@ const LaunchProgress: React.FunctionComponent = () => { const { __ } = useI18n(); const { currentStep, LaunchSequence } = useSelect( ( select ) => { - const launchStore = select( LAUNCH_STORE ); + const launchStore: LaunchSelect = select( LAUNCH_STORE ); return { currentStep: launchStore.getCurrentStep(), LaunchSequence: launchStore.getLaunchSequence(), }; - } ); + }, [] ); const current = LaunchSequence.indexOf( currentStep ) + 1; const total = LaunchSequence.length; diff --git a/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/launch-sidebar/index.tsx b/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/launch-sidebar/index.tsx index 5ac9c98af1a48..01c17958b3e71 100644 --- a/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/launch-sidebar/index.tsx +++ b/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/launch-sidebar/index.tsx @@ -4,13 +4,16 @@ import { __ } from '@wordpress/i18n'; import * as React from 'react'; import LaunchMenu from '../launch-menu'; import { LAUNCH_STORE } from '../stores'; - +import type { LaunchSelect } from '@automattic/data-stores'; import './styles.scss'; const LaunchSidebar: React.FunctionComponent = () => { const { setStep, unsetSidebarFullscreen } = useDispatch( LAUNCH_STORE ); - const LaunchSequence = useSelect( ( select ) => select( LAUNCH_STORE ).getLaunchSequence() ); + const LaunchSequence = useSelect( + ( select ) => ( select( LAUNCH_STORE ) as LaunchSelect ).getLaunchSequence(), + [] + ); const handleStart = () => { setStep( LaunchSequence[ 0 ] ); diff --git a/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/launch-steps/final-step/index.tsx b/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/launch-steps/final-step/index.tsx index a32d18319d318..8d27de61995c5 100644 --- a/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/launch-steps/final-step/index.tsx +++ b/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/launch-steps/final-step/index.tsx @@ -22,6 +22,7 @@ import classnames from 'classnames'; import * as React from 'react'; import LaunchStepContainer, { Props as LaunchStepProps } from '../../launch-step'; import { LAUNCH_STORE, PLANS_STORE } from '../../stores'; +import type { LaunchSelect, PlansSelect } from '@automattic/data-stores'; import './styles.scss'; @@ -30,7 +31,7 @@ const TickIcon = ; const FinalStep: React.FunctionComponent< LaunchStepProps > = ( { onNextStep, onPrevStep } ) => { const { domain, LaunchStep, isStepCompleted, isFlowCompleted, planProductId } = useSelect( ( select ) => { - const launchStore = select( LAUNCH_STORE ); + const launchStore: LaunchSelect = select( LAUNCH_STORE ); return { domain: launchStore.getSelectedDomain(), LaunchStep: launchStore.getLaunchStep(), @@ -38,16 +39,20 @@ const FinalStep: React.FunctionComponent< LaunchStepProps > = ( { onNextStep, on isFlowCompleted: launchStore.isFlowCompleted(), planProductId: launchStore.getSelectedPlanProductId(), }; - } + }, + [] ); const { __, hasTranslation } = useI18n(); const locale = useLocale(); - const [ plan, planProduct ] = useSelect( ( select ) => [ - select( PLANS_STORE ).getPlanByProductId( planProductId, locale ), - select( PLANS_STORE ).getPlanProductById( planProductId ), - ] ); + const { plan, planProduct } = useSelect( + ( select ) => ( { + plan: ( select( PLANS_STORE ) as PlansSelect ).getPlanByProductId( planProductId, locale ), + planProduct: ( select( PLANS_STORE ) as PlansSelect ).getPlanProductById( planProductId ), + } ), + [ planProductId, locale ] + ); const { title } = useTitle(); const { siteSubdomain } = useSiteDomains(); diff --git a/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/launch-steps/plan-step/index.tsx b/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/launch-steps/plan-step/index.tsx index ed9daae679281..baad84195aa18 100644 --- a/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/launch-steps/plan-step/index.tsx +++ b/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/launch-steps/plan-step/index.tsx @@ -6,18 +6,19 @@ import { __, sprintf } from '@wordpress/i18n'; import * as React from 'react'; import LaunchStepContainer, { Props as LaunchStepProps } from '../../launch-step'; import { LAUNCH_STORE } from '../../stores'; +import type { LaunchSelect } from '@automattic/data-stores'; import './styles.scss'; const PlanStep: React.FunctionComponent< LaunchStepProps > = ( { onPrevStep, onNextStep } ) => { const { domain, LaunchStep, selectedPlanProductId } = useSelect( ( select ) => { - const launchStore = select( LAUNCH_STORE ); + const launchStore: LaunchSelect = select( LAUNCH_STORE ); return { domain: launchStore.getSelectedDomain(), LaunchStep: launchStore.getLaunchStep(), selectedPlanProductId: launchStore.getSelectedPlanProductId(), }; - } ); + }, [] ); const { setPlanProductId, setStep } = useDispatch( LAUNCH_STORE ); diff --git a/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/launch/index.tsx b/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/launch/index.tsx index fe3a36ea612e1..6873521232977 100644 --- a/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/launch/index.tsx +++ b/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/launch/index.tsx @@ -5,18 +5,28 @@ import FinalStep from '../launch-steps/final-step'; import NameStep from '../launch-steps/name-step'; import PlanStep from '../launch-steps/plan-step'; import { LAUNCH_STORE } from '../stores'; +import type { LaunchSelect } from '@automattic/data-stores'; interface Props { onSubmit?: () => void; } const Launch: React.FunctionComponent< Props > = ( { onSubmit } ) => { - const { step: currentStep } = useSelect( ( select ) => select( LAUNCH_STORE ).getState() ); - - const LaunchStep = useSelect( ( select ) => select( LAUNCH_STORE ).getLaunchStep() ); - const LaunchSequence = useSelect( ( select ) => select( LAUNCH_STORE ).getLaunchSequence() ); - const firstIncompleteStep = useSelect( ( select ) => - select( LAUNCH_STORE ).getFirstIncompleteStep() + const { step: currentStep } = useSelect( + ( select ) => ( select( LAUNCH_STORE ) as LaunchSelect ).getState(), + [] + ); + const LaunchStep = useSelect( + ( select ) => ( select( LAUNCH_STORE ) as LaunchSelect ).getLaunchStep(), + [] + ); + const LaunchSequence = useSelect( + ( select ) => ( select( LAUNCH_STORE ) as LaunchSelect ).getLaunchSequence(), + [] + ); + const firstIncompleteStep = useSelect( + ( select ) => ( select( LAUNCH_STORE ) as LaunchSelect ).getFirstIncompleteStep(), + [] ); const { setStep, setSidebarFullscreen, unsetSidebarFullscreen } = useDispatch( LAUNCH_STORE ); diff --git a/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-patterns-plugin.tsx b/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-patterns-plugin.tsx index 7033aa5ee0376..158a61514d4d3 100644 --- a/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-patterns-plugin.tsx +++ b/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/page-patterns-plugin.tsx @@ -3,7 +3,8 @@ import { useSelect, useDispatch } from '@wordpress/data'; import { useCallback } from '@wordpress/element'; import { addFilter, removeFilter } from '@wordpress/hooks'; import { __ } from '@wordpress/i18n'; - +import { selectors as starterPageTemplatesSelectors } from '../starter-page-templates/store'; +import type { SelectFromMap } from '@automattic/data-stores'; import '@wordpress/nux'; const INSERTING_HOOK_NAME = 'isInsertingPagePattern'; @@ -12,6 +13,17 @@ const INSERTING_HOOK_NAMESPACE = 'automattic/full-site-editing/inserting-pattern interface PagePatternsPluginProps { patterns: PatternDefinition[]; } +type StarterPageTemplatesSelectors = SelectFromMap< typeof starterPageTemplatesSelectors >; +type CoreEditorPlaceholder = { + getBlocks: ( ...args: unknown[] ) => Array< { name: string; clientId: string } >; + getEditedPostAttribute: ( ...args: unknown[] ) => unknown; +}; +type CoreEditPostPlaceholder = { + isFeatureActive: ( ...args: unknown[] ) => boolean; +}; +type CoreNuxPlaceholder = { + areTipsEnabled: ( ...args: unknown[] ) => boolean; +}; export function PagePatternsPlugin( props: PagePatternsPluginProps ) { const { setOpenState } = useDispatch( 'automattic/starter-page-layouts' ); @@ -22,12 +34,16 @@ export function PagePatternsPlugin( props: PagePatternsPluginProps ) { const { disableTips } = useDispatch( 'core/nux' ); const selectProps = useSelect( ( select ) => { - const { isOpen, isPatternPicker } = select( 'automattic/starter-page-layouts' ); + const { isOpen, isPatternPicker }: StarterPageTemplatesSelectors = select( + 'automattic/starter-page-layouts' + ); return { isOpen: isOpen(), - isWelcomeGuideActive: select( 'core/edit-post' ).isFeatureActive( 'welcomeGuide' ) as boolean, // Gutenberg 7.2.0 or higher + isWelcomeGuideActive: ( + select( 'core/edit-post' ) as CoreEditPostPlaceholder + ).isFeatureActive( 'welcomeGuide' ) as boolean, // Gutenberg 7.2.0 or higher areTipsEnabled: select( 'core/nux' ) - ? ( select( 'core/nux' ).areTipsEnabled() as boolean ) + ? ( ( select( 'core/nux' ) as CoreNuxPlaceholder ).areTipsEnabled() as boolean ) : false, // Gutenberg 7.1.0 or lower ...( isPatternPicker() && { title: __( 'Choose a Pattern', 'full-site-editing' ), @@ -37,21 +53,22 @@ export function PagePatternsPlugin( props: PagePatternsPluginProps ) { ), } ), }; - } ); + }, [] ); const { getMeta, postContentBlock } = useSelect( ( select ) => { - const getMeta = () => select( 'core/editor' ).getEditedPostAttribute( 'meta' ); - const currentBlocks = select( 'core/editor' ).getBlocks(); + const getMeta = () => + ( select( 'core/editor' ) as CoreEditorPlaceholder ).getEditedPostAttribute( 'meta' ); + const currentBlocks = ( select( 'core/editor' ) as CoreEditorPlaceholder ).getBlocks(); return { getMeta, postContentBlock: currentBlocks.find( ( block ) => block.name === 'a8c/post-content' ), }; - } ); + }, [] ); const savePatternChoice = useCallback( ( name: string ) => { // Save selected pattern slug in meta. - const currentMeta = getMeta(); + const currentMeta = getMeta() as Record< string, unknown >; editPost( { meta: { ...currentMeta, diff --git a/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/store.ts b/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/store.ts index 3ab0fb58c0795..c52d75e2dd8e1 100644 --- a/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/store.ts +++ b/apps/editing-toolkit/editing-toolkit-plugin/starter-page-templates/store.ts @@ -14,7 +14,7 @@ const actions = { } ), }; -const selectors = { +export const selectors = { isOpen: ( state: OpenState ): boolean => 'CLOSED' !== state, isPatternPicker: ( state: OpenState ): boolean => 'OPEN_FOR_BLANK_CANVAS' === state, }; @@ -30,11 +30,3 @@ registerStore( STORE_KEY, { actions, selectors, } ); - -declare module '@wordpress/data' { - function dispatch( key: 'automattic/starter-page-layouts' ): typeof actions; - function select( key: 'automattic/starter-page-layouts' ): { - isOpen: () => ReturnType< typeof selectors.isOpen >; - isPatternPicker: () => ReturnType< typeof selectors.isPatternPicker >; - }; -} diff --git a/apps/editing-toolkit/editing-toolkit-plugin/wpcom-block-editor-nav-sidebar/src/attach-sidebar.tsx b/apps/editing-toolkit/editing-toolkit-plugin/wpcom-block-editor-nav-sidebar/src/attach-sidebar.tsx index e517bea30da3d..0c14cece2673f 100644 --- a/apps/editing-toolkit/editing-toolkit-plugin/wpcom-block-editor-nav-sidebar/src/attach-sidebar.tsx +++ b/apps/editing-toolkit/editing-toolkit-plugin/wpcom-block-editor-nav-sidebar/src/attach-sidebar.tsx @@ -5,6 +5,10 @@ import { registerPlugin as originalRegisterPlugin, PluginSettings } from '@wordp import WpcomBlockEditorNavSidebar from './components/nav-sidebar'; import ToggleSidebarButton from './components/toggle-sidebar-button'; +type CoreEditPostPlaceholder = { + isFeatureActive: ( ...args: unknown[] ) => boolean; +}; + const registerPlugin = ( name: string, settings: Omit< PluginSettings, 'icon' > ) => originalRegisterPlugin( name, settings as PluginSettings ); @@ -38,11 +42,15 @@ if ( typeof MainDashboardButton !== 'undefined' ) { } ); // Uses presence of data store to detect whether this is the experimental site editor. - const isSiteEditor = useSelect( ( select ) => !! select( 'core/edit-site' ) ); + const isSiteEditor = useSelect( ( select ) => !! select( 'core/edit-site' ), [] ); // Disable sidebar nav if the editor is not in fullscreen mode - const isFullscreenActive = useSelect( ( select ) => - select( 'core/edit-post' ).isFeatureActive( 'fullscreenMode' ) + const isFullscreenActive = useSelect( + ( select ) => + ( select( 'core/edit-post' ) as CoreEditPostPlaceholder ).isFeatureActive( + 'fullscreenMode' + ), + [] ); if ( isSiteEditor || ! isFullscreenActive ) { diff --git a/apps/editing-toolkit/editing-toolkit-plugin/wpcom-block-editor-nav-sidebar/src/components/nav-sidebar/index.tsx b/apps/editing-toolkit/editing-toolkit-plugin/wpcom-block-editor-nav-sidebar/src/components/nav-sidebar/index.tsx index 15a2c42ec60b1..fe728849f5a68 100644 --- a/apps/editing-toolkit/editing-toolkit-plugin/wpcom-block-editor-nav-sidebar/src/components/nav-sidebar/index.tsx +++ b/apps/editing-toolkit/editing-toolkit-plugin/wpcom-block-editor-nav-sidebar/src/components/nav-sidebar/index.tsx @@ -4,7 +4,6 @@ import { IsolatedEventContainer, withConstrainedTabbing, } from '@wordpress/components'; -import { compose } from '@wordpress/compose'; import { useDispatch, useSelect } from '@wordpress/data'; import { forwardRef, useLayoutEffect, useRef, useEffect } from '@wordpress/element'; import { applyFilters, doAction, hasAction } from '@wordpress/hooks'; @@ -16,14 +15,29 @@ import { addQueryArgs } from '@wordpress/url'; import classNames from 'classnames'; import { get, isEmpty, partition } from 'lodash'; import * as React from 'react'; +import { selectors as wpcomBlockEditorNavSidebarSelectors } from '../../../../wpcom-block-editor-nav-sidebar/src/store'; import { STORE_KEY, POST_IDS_TO_EXCLUDE } from '../../constants'; import { Post } from '../../types'; import CreatePage from '../create-page'; import NavItem from '../nav-item'; import SiteIcon from '../site-icon'; +import type { SelectFromMap } from '@automattic/data-stores'; import './style.scss'; +type WpcomBlockEditorNavSidebarSelectors = SelectFromMap< + typeof wpcomBlockEditorNavSidebarSelectors +>; +type CoreEditorPlaceholder = { + isEditedPostNew: ( ...args: unknown[] ) => boolean; + getCurrentPostId: ( ...args: unknown[] ) => number; + getCurrentPostType: ( ...args: unknown[] ) => string; + getEditedPostAttribute: ( ...args: unknown[] ) => unknown; +}; +type CorePlaceholder = { + getEntityRecords: ( ...args: unknown[] ) => Array< unknown > | null; +}; + const Button = forwardRef( ( { @@ -43,20 +57,24 @@ const Button = forwardRef( function WpcomBlockEditorNavSidebar() { const { toggleSidebar, setSidebarClosing } = useDispatch( STORE_KEY ); - const [ isOpen, isClosing, postType, selectedItemId, siteTitle ] = useSelect( ( select ) => { + const { isOpen, isClosing, postType, selectedItemId, siteTitle } = useSelect( ( select ) => { const { getPostType, getSite } = select( 'core' ) as unknown as { getPostType: ( postType: string ) => null | { slug: string }; getSite: () => null | { title: string }; }; - return [ - select( STORE_KEY ).isSidebarOpened(), - select( STORE_KEY ).isSidebarClosing(), - getPostType( select( 'core/editor' ).getCurrentPostType() ), - select( 'core/editor' ).getCurrentPostId(), - getSite()?.title, - ]; - } ); + const blockEditorNavSidebarSelect: WpcomBlockEditorNavSidebarSelectors = select( STORE_KEY ); + + return { + isOpen: blockEditorNavSidebarSelect.isSidebarOpened(), + isClosing: blockEditorNavSidebarSelect.isSidebarClosing(), + postType: getPostType( + ( select( 'core/editor' ) as CoreEditorPlaceholder ).getCurrentPostType() + ), + selectedItemId: ( select( 'core/editor' ) as CoreEditorPlaceholder ).getCurrentPostId(), + siteTitle: getSite()?.title, + }; + }, [] ); const siteSlug = window?.location.host; @@ -298,7 +316,7 @@ function WpcomBlockEditorNavSidebar() { ); } -export default compose( [ withConstrainedTabbing ] )( WpcomBlockEditorNavSidebar ); +export default withConstrainedTabbing( WpcomBlockEditorNavSidebar ); type NavItemRecord = { current: Post[]; @@ -307,9 +325,18 @@ type NavItemRecord = { }; function useNavItems(): NavItemRecord { return useSelect( ( select ) => { - const { isEditedPostNew, getCurrentPostId, getCurrentPostType, getEditedPostAttribute } = - select( 'core/editor' ); - const statuses = select( 'core' ).getEntityRecords( 'root', 'status', { context: 'edit' } ); + const { + isEditedPostNew, + getCurrentPostId, + getCurrentPostType, + getEditedPostAttribute, + }: CoreEditorPlaceholder = select( 'core/editor' ); + const statuses = ( select( 'core' ) as CorePlaceholder ).getEntityRecords( 'root', 'status', { + context: 'edit', + } ) as Array< { + show_in_list: boolean; + slug: string; + } > | null; if ( ! statuses ) { return { current: [], drafts: [], recent: [] }; @@ -321,13 +348,17 @@ function useNavItems(): NavItemRecord { .join( ',' ); const currentPostId = getCurrentPostId(); const currentPostType = getCurrentPostType(); - const items = ( select( 'core' ).getEntityRecords( 'postType', currentPostType, { - _fields: 'id,status,title', - exclude: [ currentPostId, ...POST_IDS_TO_EXCLUDE ], - orderby: 'modified', - per_page: 10, - status: statusFilter, - } ) || [] ) as Post[]; + const items = ( ( select( 'core' ) as CorePlaceholder ).getEntityRecords( + 'postType', + currentPostType, + { + _fields: 'id,status,title', + exclude: [ currentPostId, ...POST_IDS_TO_EXCLUDE ], + orderby: 'modified', + per_page: 10, + status: statusFilter, + } + ) || [] ) as Post[]; const current = { id: currentPostId, status: isEditedPostNew() ? 'draft' : getEditedPostAttribute( 'status' ), @@ -336,15 +367,15 @@ function useNavItems(): NavItemRecord { const [ drafts, recent ] = partition( items, { status: 'draft' } ); return { current: [ current ], drafts, recent }; - } ); + }, [] ); } function usePostStatusLabels(): Record< string, string > { return useSelect( ( select ) => { - const items = select( 'core' ).getEntityRecords( 'root', 'status' ); - return ( items || [] ).reduce( + const items = ( select( 'core' ) as CorePlaceholder ).getEntityRecords( 'root', 'status' ); + return ( ( items || [] ) as Array< { name: string; slug: string } > ).reduce( ( acc, { name, slug } ) => ( slug === 'publish' ? acc : { ...acc, [ slug ]: name } ), {} ); - } ); + }, [] ); } diff --git a/apps/editing-toolkit/editing-toolkit-plugin/wpcom-block-editor-nav-sidebar/src/components/site-icon/index.tsx b/apps/editing-toolkit/editing-toolkit-plugin/wpcom-block-editor-nav-sidebar/src/components/site-icon/index.tsx index 12146b50fe716..c864c8b6813ff 100644 --- a/apps/editing-toolkit/editing-toolkit-plugin/wpcom-block-editor-nav-sidebar/src/components/site-icon/index.tsx +++ b/apps/editing-toolkit/editing-toolkit-plugin/wpcom-block-editor-nav-sidebar/src/components/site-icon/index.tsx @@ -2,12 +2,16 @@ import { useSelect } from '@wordpress/data'; import { __ } from '@wordpress/i18n'; import { Icon, wordpress } from '@wordpress/icons'; +type CorePlaceholder = { + getEntityRecord: ( ...args: unknown[] ) => { site_icon_url?: string } | null; +}; + export default function SiteIcon() { // The site icon url should be available from /wp/v2/settings or similar in the future, // but for now it's accessible at the index endpoint. // https://github.com/WordPress/gutenberg/blob/68c3978be352c6d3982f73bcf8c80744608c53c8/lib/init.php#L160 const siteIconUrl: string | undefined = useSelect( ( select ) => { - const { getEntityRecord } = select( 'core' ); + const { getEntityRecord }: CorePlaceholder = select( 'core' ); // getEntityRecord usually takes a key to get a specific entity, but here we pass undefined to get the "root" entity. // While this works, the function isn't typed this way, so casting undefined as number to prevent compiler errors. const siteData = diff --git a/apps/editing-toolkit/editing-toolkit-plugin/wpcom-block-editor-nav-sidebar/src/components/toggle-sidebar-button/index.tsx b/apps/editing-toolkit/editing-toolkit-plugin/wpcom-block-editor-nav-sidebar/src/components/toggle-sidebar-button/index.tsx index a52748e3ef8c8..b30ce68f3f555 100644 --- a/apps/editing-toolkit/editing-toolkit-plugin/wpcom-block-editor-nav-sidebar/src/components/toggle-sidebar-button/index.tsx +++ b/apps/editing-toolkit/editing-toolkit-plugin/wpcom-block-editor-nav-sidebar/src/components/toggle-sidebar-button/index.tsx @@ -3,11 +3,16 @@ import { Button as OriginalButton } from '@wordpress/components'; import { useDispatch, useSelect } from '@wordpress/data'; import { __ } from '@wordpress/i18n'; import classnames from 'classnames'; +import { selectors as wpcomBlockEditorNavSidebarSelectors } from '../../../../wpcom-block-editor-nav-sidebar/src/store'; import { STORE_KEY } from '../../constants'; import SiteIcon from '../site-icon'; - +import type { SelectFromMap } from '@automattic/data-stores'; import './style.scss'; +type WpcomBlockEditorNavSidebarSelectors = SelectFromMap< + typeof wpcomBlockEditorNavSidebarSelectors +>; + const Button = ( { children, ...rest @@ -17,7 +22,10 @@ const Button = ( { export default function ToggleSidebarButton() { const { toggleSidebar } = useDispatch( STORE_KEY ); - const isSidebarOpen = useSelect( ( select ) => select( STORE_KEY ).isSidebarOpened() ); + const isSidebarOpen = useSelect( + ( select ) => ( select( STORE_KEY ) as WpcomBlockEditorNavSidebarSelectors ).isSidebarOpened(), + [] + ); const handleClick = () => { recordTracksEvent( `calypso_editor_sidebar_open` ); diff --git a/apps/editing-toolkit/editing-toolkit-plugin/wpcom-block-editor-nav-sidebar/src/store.ts b/apps/editing-toolkit/editing-toolkit-plugin/wpcom-block-editor-nav-sidebar/src/store.ts index b383f2ae5b52b..7ad092048aeba 100644 --- a/apps/editing-toolkit/editing-toolkit-plugin/wpcom-block-editor-nav-sidebar/src/store.ts +++ b/apps/editing-toolkit/editing-toolkit-plugin/wpcom-block-editor-nav-sidebar/src/store.ts @@ -1,7 +1,6 @@ import { combineReducers, registerStore } from '@wordpress/data'; import { actions, Action } from './actions'; import { STORE_KEY } from './constants'; -import type { DispatchFromMap, SelectFromMap } from '@automattic/data-stores'; import type { Reducer } from 'redux'; const opened: Reducer< boolean, Action > = ( state = false, action ) => { @@ -28,7 +27,7 @@ const reducer = combineReducers( { opened, closing } ); type State = ReturnType< typeof reducer >; -const selectors = { +export const selectors = { isSidebarOpened: ( state: State ) => state.opened, isSidebarClosing: ( state: State ) => state.closing, }; @@ -38,8 +37,3 @@ registerStore( STORE_KEY, { reducer, selectors, } ); - -declare module '@wordpress/data' { - function dispatch( key: typeof STORE_KEY ): DispatchFromMap< typeof actions >; - function select( key: typeof STORE_KEY ): SelectFromMap< typeof selectors >; -} diff --git a/apps/editing-toolkit/editing-toolkit-plugin/wpcom-block-editor-nux/src/post-published-modal/index.tsx b/apps/editing-toolkit/editing-toolkit-plugin/wpcom-block-editor-nux/src/post-published-modal/index.tsx index 991c8e8c14825..b3f1d32127327 100644 --- a/apps/editing-toolkit/editing-toolkit-plugin/wpcom-block-editor-nux/src/post-published-modal/index.tsx +++ b/apps/editing-toolkit/editing-toolkit-plugin/wpcom-block-editor-nux/src/post-published-modal/index.tsx @@ -5,23 +5,42 @@ import { useEffect, useRef, useState } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; import React from 'react'; import NuxModal from '../nux-modal'; +import { selectors as wpcomWelcomeGuideSelectors } from '../store'; import postPublishedImage from './images/post-published.svg'; - +import type { SelectFromMap } from '@automattic/data-stores'; import './style.scss'; +type WpcomWelcomeGuideSelectors = SelectFromMap< typeof wpcomWelcomeGuideSelectors >; +type CoreEditorPlaceholder = { + getCurrentPost: ( ...args: unknown[] ) => { link: string }; + getCurrentPostType: ( ...args: unknown[] ) => string; + isCurrentPostPublished: ( ...args: unknown[] ) => boolean; +}; + /** * Show the first post publish modal */ const PostPublishedModal: React.FC = () => { - const { link } = useSelect( ( select ) => select( 'core/editor' ).getCurrentPost() ); - const postType = useSelect( ( select ) => select( 'core/editor' ).getCurrentPostType() ); + const { link } = useSelect( + ( select ) => ( select( 'core/editor' ) as CoreEditorPlaceholder ).getCurrentPost(), + [] + ); + const postType = useSelect( + ( select ) => ( select( 'core/editor' ) as CoreEditorPlaceholder ).getCurrentPostType(), + [] + ); - const isCurrentPostPublished = useSelect( ( select ) => - select( 'core/editor' ).isCurrentPostPublished() + const isCurrentPostPublished = useSelect( + ( select ) => ( select( 'core/editor' ) as CoreEditorPlaceholder ).isCurrentPostPublished(), + [] ); const previousIsCurrentPostPublished = useRef( isCurrentPostPublished ); - const shouldShowFirstPostPublishedModal = useSelect( ( select ) => - select( 'automattic/wpcom-welcome-guide' ).getShouldShowFirstPostPublishedModal() + const shouldShowFirstPostPublishedModal = useSelect( + ( select ) => + ( + select( 'automattic/wpcom-welcome-guide' ) as WpcomWelcomeGuideSelectors + ).getShouldShowFirstPostPublishedModal(), + [] ); const [ isOpen, setIsOpen ] = useState( false ); const closeModal = () => setIsOpen( false ); diff --git a/apps/editing-toolkit/editing-toolkit-plugin/wpcom-block-editor-nux/src/store.js b/apps/editing-toolkit/editing-toolkit-plugin/wpcom-block-editor-nux/src/store.js index 08efd335d3517..ccb1aa6c62b8c 100644 --- a/apps/editing-toolkit/editing-toolkit-plugin/wpcom-block-editor-nux/src/store.js +++ b/apps/editing-toolkit/editing-toolkit-plugin/wpcom-block-editor-nux/src/store.js @@ -130,7 +130,7 @@ const actions = { } ), }; -const selectors = { +export const selectors = { isWelcomeGuideManuallyOpened: ( state ) => state.welcomeGuideManuallyOpened, isWelcomeGuideShown: ( state ) => !! state.showWelcomeGuide, isWelcomeGuideStatusLoaded: ( state ) => typeof state.showWelcomeGuide !== 'undefined', diff --git a/apps/editing-toolkit/editing-toolkit-plugin/wpcom-block-editor-nux/src/welcome-tour/tour-launch.tsx b/apps/editing-toolkit/editing-toolkit-plugin/wpcom-block-editor-nux/src/welcome-tour/tour-launch.tsx index deecf80e07a87..66be472b7c67d 100644 --- a/apps/editing-toolkit/editing-toolkit-plugin/wpcom-block-editor-nux/src/welcome-tour/tour-launch.tsx +++ b/apps/editing-toolkit/editing-toolkit-plugin/wpcom-block-editor-nux/src/welcome-tour/tour-launch.tsx @@ -6,21 +6,44 @@ import { useDispatch, useSelect, dispatch } from '@wordpress/data'; import { useEffect, useMemo } from '@wordpress/element'; import useSiteIntent from '../../../dotcom-fse/lib/site-intent/use-site-intent'; import useSitePlan from '../../../dotcom-fse/lib/site-plan/use-site-plan'; +import { selectors as starterPageTemplatesSelectors } from '../../../starter-page-templates/store'; +import { selectors as wpcomBlockEditorNavSidebarSelectors } from '../../../wpcom-block-editor-nav-sidebar/src/store'; +import { selectors as wpcomWelcomeGuideSelectors } from '../store'; import { getEditorType } from './get-editor-type'; import getTourSteps from './tour-steps'; import './style-tour.scss'; +import type { SelectFromMap } from '@automattic/data-stores'; import type { WpcomConfig } from '@automattic/tour-kit'; import type { Rect, Placement } from '@popperjs/core'; +type StarterPageTemplatesSelectors = SelectFromMap< typeof starterPageTemplatesSelectors >; +type WpcomBlockEditorNavSidebarSelectors = SelectFromMap< + typeof wpcomBlockEditorNavSidebarSelectors +>; +type WpcomWelcomeGuideSelectors = SelectFromMap< typeof wpcomWelcomeGuideSelectors >; +type CoreEditPostPlaceholder = { + isInserterOpened: ( ...args: unknown[] ) => boolean; +}; +type CoreInterfacePlaceholder = { + getActiveComplementaryArea: ( name: string ) => string; +}; + function LaunchWpcomWelcomeTour() { - const { show, isNewPageLayoutModalOpen, isManuallyOpened } = useSelect( ( select ) => ( { - show: select( 'automattic/wpcom-welcome-guide' ).isWelcomeGuideShown(), - // Handle the case where the new page pattern modal is initialized and open - isNewPageLayoutModalOpen: - select( 'automattic/starter-page-layouts' ) && - select( 'automattic/starter-page-layouts' ).isOpen(), - isManuallyOpened: select( 'automattic/wpcom-welcome-guide' ).isWelcomeGuideManuallyOpened(), - } ) ); + const { show, isNewPageLayoutModalOpen, isManuallyOpened } = useSelect( + ( select ) => ( { + show: ( + select( 'automattic/wpcom-welcome-guide' ) as WpcomWelcomeGuideSelectors + ).isWelcomeGuideShown(), + // Handle the case where the new page pattern modal is initialized and open + isNewPageLayoutModalOpen: + select( 'automattic/starter-page-layouts' ) && + ( select( 'automattic/starter-page-layouts' ) as StarterPageTemplatesSelectors ).isOpen(), + isManuallyOpened: ( + select( 'automattic/wpcom-welcome-guide' ) as WpcomWelcomeGuideSelectors + ).isWelcomeGuideManuallyOpened(), + } ), + [] + ); const { siteIntent, siteIntentFetched } = useSiteIntent(); const localeSlug = useLocale(); const editorType = getEditorType(); @@ -68,7 +91,7 @@ function WelcomeTour( { siteIntent }: { siteIntent?: string } ) { const isWelcomeTourNext = () => { return new URLSearchParams( document.location.search ).has( 'welcome-tour-next' ); }; - const isSiteEditor = useSelect( ( select ) => !! select( 'core/edit-site' ) ); + const isSiteEditor = useSelect( ( select ) => !! select( 'core/edit-site' ), [] ); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore Until `@types/wordpress__editor` (which has `@types/wordpress__core-data` as a dependency) can be upgraded to a version that includes `getCurrentTheme` // the function has existed for many years, and works as expected on wpcom and atomic @@ -88,13 +111,24 @@ function WelcomeTour( { siteIntent }: { siteIntent?: string } ) { const paymentBlockIndex = tourSteps.findIndex( ( step ) => step.slug === 'payment-block' ); tourSteps.splice( paymentBlockIndex, 1 ); } - const { isInserterOpened, isSidebarOpened, isSettingsOpened } = useSelect( ( select ) => ( { - isInserterOpened: select( 'core/edit-post' ).isInserterOpened(), - isSidebarOpened: select( 'automattic/block-editor-nav-sidebar' )?.isSidebarOpened() ?? false, // The sidebar store may not always be loaded. - isSettingsOpened: - select( 'core/interface' ).getActiveComplementaryArea( 'core/edit-post' ) === - 'edit-post/document', - } ) ); + const { isInserterOpened, isSidebarOpened, isSettingsOpened } = useSelect( + ( select ) => ( { + isInserterOpened: ( + select( 'core/edit-post' ) as CoreEditPostPlaceholder + ).isInserterOpened(), + isSidebarOpened: + ( + select( 'automattic/block-editor-nav-sidebar' ) as + | WpcomBlockEditorNavSidebarSelectors + | undefined + )?.isSidebarOpened() ?? false, // The sidebar store may not always be loaded. + isSettingsOpened: + ( select( 'core/interface' ) as CoreInterfacePlaceholder ).getActiveComplementaryArea( + 'core/edit-post' + ) === 'edit-post/document', + } ), + [] + ); const isTourMinimized = isSidebarOpened || @@ -119,8 +153,12 @@ function WelcomeTour( { siteIntent }: { siteIntent?: string } ) { tourRating: { enabled: true, useTourRating: () => { - return useSelect( ( select ) => - select( 'automattic/wpcom-welcome-guide' ).getTourRating() + return useSelect( + ( select ) => + ( + select( 'automattic/wpcom-welcome-guide' ) as WpcomWelcomeGuideSelectors + ).getTourRating(), + [] ); }, onTourRate: ( rating ) => { diff --git a/apps/editing-toolkit/package.json b/apps/editing-toolkit/package.json index ffde5010721c3..cad6b74a5034a 100644 --- a/apps/editing-toolkit/package.json +++ b/apps/editing-toolkit/package.json @@ -72,39 +72,39 @@ "@emotion/react": "^11.4.1", "@popperjs/core": "^2.10.2", "@sentry/browser": "^7.33.0", - "@wordpress/a11y": "^3.9.0", - "@wordpress/api-fetch": "^6.6.0", - "@wordpress/base-styles": "^4.5.0", - "@wordpress/block-editor": "^9.1.0", - "@wordpress/blocks": "^11.8.0", - "@wordpress/components": "^19.15.0", - "@wordpress/compose": "^5.7.0", - "@wordpress/data": "^6.9.0", - "@wordpress/data-controls": "^2.9.0", - "@wordpress/date": "^4.9.0", - "@wordpress/dependency-extraction-webpack-plugin": "^3.5.0", - "@wordpress/dom-ready": "^3.9.0", - "@wordpress/edit-post": "^6.6.0", - "@wordpress/editor": "^12.8.0", - "@wordpress/element": "^4.7.0", + "@wordpress/a11y": "^3.22.0", + "@wordpress/api-fetch": "^6.19.0", + "@wordpress/base-styles": "^4.13.0", + "@wordpress/block-editor": "^10.5.0", + "@wordpress/blocks": "^11.21.0", + "@wordpress/components": "^22.1.0", + "@wordpress/compose": "^5.20.0", + "@wordpress/data": "^7.6.0", + "@wordpress/data-controls": "^2.22.0", + "@wordpress/date": "^4.22.0", + "@wordpress/dependency-extraction-webpack-plugin": "^4.5.0", + "@wordpress/dom-ready": "^3.22.0", + "@wordpress/edit-post": "^6.19.0", + "@wordpress/editor": "^12.21.0", + "@wordpress/element": "^4.20.0", "@wordpress/env": "^4.7.0", - "@wordpress/escape-html": "^2.9.0", - "@wordpress/hooks": "^3.9.0", - "@wordpress/html-entities": "^3.9.0", - "@wordpress/i18n": "^4.9.0", - "@wordpress/icons": "^9.0.0", - "@wordpress/interface": "^4.8.0", - "@wordpress/is-shallow-equal": "^4.9.0", - "@wordpress/keycodes": "^3.9.0", - "@wordpress/notices": "^3.10.0", - "@wordpress/nux": "^5.7.0", - "@wordpress/plugins": "^4.7.0", - "@wordpress/primitives": "^3.7.0", - "@wordpress/react-i18n": "^3.7.0", - "@wordpress/rich-text": "^5.7.0", - "@wordpress/scripts": "^23.1.0", - "@wordpress/server-side-render": "^3.7.0", - "@wordpress/url": "^3.10.0", + "@wordpress/escape-html": "^2.22.0", + "@wordpress/hooks": "^3.22.0", + "@wordpress/html-entities": "^3.22.0", + "@wordpress/i18n": "^4.22.0", + "@wordpress/icons": "^9.13.0", + "@wordpress/interface": "^4.21.0", + "@wordpress/is-shallow-equal": "^4.22.0", + "@wordpress/keycodes": "^3.22.0", + "@wordpress/notices": "^3.22.0", + "@wordpress/nux": "^5.20.0", + "@wordpress/plugins": "^4.20.0", + "@wordpress/primitives": "^3.20.0", + "@wordpress/react-i18n": "^3.20.0", + "@wordpress/rich-text": "^5.20.0", + "@wordpress/scripts": "^24.6.0", + "@wordpress/server-side-render": "^3.20.0", + "@wordpress/url": "^3.23.0", "calypso": "workspace:^", "classnames": "^2.3.1", "eslint": "^8.34.0", @@ -132,9 +132,9 @@ "@testing-library/react": "^12.1.3", "@types/node": "^18.11.18", "@types/wordpress__plugins": "^3.0.0", - "@wordpress/eslint-plugin": "^12.3.0", - "@wordpress/jest-preset-default": "^8.2.0", - "@wordpress/readable-js-assets-webpack-plugin": "^1.0.4", + "@wordpress/eslint-plugin": "^13.6.0", + "@wordpress/jest-preset-default": "^10.3.0", + "@wordpress/readable-js-assets-webpack-plugin": "^2.5.0", "babel-jest": "^27.5.1", "jest-teamcity": "^1.9.0", "wait-for-expect": "^3.0.2", diff --git a/apps/happy-blocks/package.json b/apps/happy-blocks/package.json index 2ddf46d188f03..ca39a445adfae 100644 --- a/apps/happy-blocks/package.json +++ b/apps/happy-blocks/package.json @@ -32,12 +32,12 @@ "@automattic/wp-babel-makepot": "workspace:^", "@automattic/wpcom-template-parts": "workspace:^", "@emotion/styled": "^11.3.0", - "@wordpress/base-styles": "^4.5.0", - "@wordpress/block-editor": "^9.1.0", - "@wordpress/blocks": "^11.8.0", - "@wordpress/components": "^19.15.0", - "@wordpress/element": "^4.7.0", - "@wordpress/i18n": "^4.9.0", + "@wordpress/base-styles": "^4.13.0", + "@wordpress/block-editor": "^10.5.0", + "@wordpress/blocks": "^11.21.0", + "@wordpress/components": "^22.1.0", + "@wordpress/element": "^4.20.0", + "@wordpress/i18n": "^4.22.0", "classnames": "^2.3.2", "glob": "^7.1.6", "i18n-calypso": "workspace:^", @@ -48,7 +48,7 @@ "@automattic/calypso-apps-builder": "workspace:^", "@emotion/react": "^11.4.1", "@testing-library/react": "^12.1.3", - "@wordpress/readable-js-assets-webpack-plugin": "^1.0.4", + "@wordpress/readable-js-assets-webpack-plugin": "^2.5.0", "copy-webpack-plugin": "^10.1.0", "glob": "^7.1.6", "jest": "^27.3.1", @@ -56,6 +56,6 @@ "webpack": "^5.68.0" }, "peerDependencies": { - "@wordpress/data": "^6.1.5" + "@wordpress/data": "^7.6.0" } } diff --git a/apps/happychat/package.json b/apps/happychat/package.json index 138528bcaf0f6..6d83b65b5cc57 100644 --- a/apps/happychat/package.json +++ b/apps/happychat/package.json @@ -28,8 +28,8 @@ "@automattic/calypso-polyfills": "workspace:^", "@automattic/components": "workspace:^", "@automattic/happychat-connection": "workspace:^", - "@wordpress/data": "^6.7.0", - "@wordpress/icons": "^8.3.0", + "@wordpress/data": "^7.6.0", + "@wordpress/icons": "^9.13.0", "calypso": "workspace:^", "react": "^17.0.2", "react-dom": "^17.0.2", diff --git a/apps/o2-blocks/package.json b/apps/o2-blocks/package.json index cae5ad9829193..2904810a72f70 100644 --- a/apps/o2-blocks/package.json +++ b/apps/o2-blocks/package.json @@ -22,19 +22,19 @@ }, "dependencies": { "@automattic/calypso-build": "workspace:^", - "@wordpress/api-fetch": "^6.6.0", - "@wordpress/base-styles": "^4.5.0", - "@wordpress/block-editor": "^9.1.0", - "@wordpress/blocks": "^11.8.0", - "@wordpress/components": "^19.15.0", - "@wordpress/data": "^6.9.0", - "@wordpress/editor": "^12.8.0", - "@wordpress/element": "^4.7.0", - "@wordpress/hooks": "^3.9.0", - "@wordpress/i18n": "^4.9.0", - "@wordpress/icons": "^9.5.0", - "@wordpress/is-shallow-equal": "^4.9.0", - "@wordpress/primitives": "^3.7.0", + "@wordpress/api-fetch": "^6.19.0", + "@wordpress/base-styles": "^4.13.0", + "@wordpress/block-editor": "^10.5.0", + "@wordpress/blocks": "^11.21.0", + "@wordpress/components": "^22.1.0", + "@wordpress/data": "^7.6.0", + "@wordpress/editor": "^12.21.0", + "@wordpress/element": "^4.20.0", + "@wordpress/hooks": "^3.22.0", + "@wordpress/i18n": "^4.22.0", + "@wordpress/icons": "^9.13.0", + "@wordpress/is-shallow-equal": "^4.22.0", + "@wordpress/primitives": "^3.20.0", "classnames": "^2.3.1", "lodash": "^4.17.21", "moment": "^2.26.0", @@ -47,7 +47,7 @@ "devDependencies": { "@automattic/calypso-apps-builder": "workspace:^", "@automattic/calypso-eslint-overrides": "workspace:^", - "@wordpress/readable-js-assets-webpack-plugin": "^1.0.4", + "@wordpress/readable-js-assets-webpack-plugin": "^2.5.0", "jest": "^27.3.1", "postcss": "^8.4.5", "webpack": "^5.68.0" diff --git a/apps/odyssey-stats/package.json b/apps/odyssey-stats/package.json index d2472f10cb3ac..b4e805f816460 100644 --- a/apps/odyssey-stats/package.json +++ b/apps/odyssey-stats/package.json @@ -52,7 +52,7 @@ "@automattic/webpack-extensive-lodash-replacement-plugin": "workspace:^", "@automattic/webpack-inline-constant-exports-plugin": "workspace:^", "@automattic/wp-babel-makepot": "workspace:^", - "@wordpress/dependency-extraction-webpack-plugin": "^4.4.0", + "@wordpress/dependency-extraction-webpack-plugin": "^4.5.0", "autoprefixer": "^10.2.5", "gettext-parser": "^6.0.0", "html-webpack-plugin": "^5.0.0-beta.4", diff --git a/apps/wpcom-block-editor/package.json b/apps/wpcom-block-editor/package.json index 4c4cd99aff502..588c35a836c39 100644 --- a/apps/wpcom-block-editor/package.json +++ b/apps/wpcom-block-editor/package.json @@ -23,24 +23,24 @@ "dependencies": { "@automattic/typography": "workspace:^", "@babel/runtime": "^7.17.2", - "@wordpress/base-styles": "^4.5.0", - "@wordpress/block-editor": "^9.1.0", - "@wordpress/blocks": "^11.8.0", - "@wordpress/components": "^19.15.0", - "@wordpress/compose": "^5.7.0", - "@wordpress/data": "^6.9.0", - "@wordpress/dom-ready": "^3.9.0", - "@wordpress/edit-post": "^6.6.0", - "@wordpress/edit-site": "^4.6.0", - "@wordpress/editor": "^12.8.0", - "@wordpress/element": "^4.7.0", - "@wordpress/hooks": "^3.9.0", - "@wordpress/i18n": "^4.9.0", - "@wordpress/icons": "^9.0.0", - "@wordpress/is-shallow-equal": "^4.9.0", - "@wordpress/plugins": "^4.7.0", - "@wordpress/rich-text": "^5.7.0", - "@wordpress/url": "^3.10.0", + "@wordpress/base-styles": "^4.13.0", + "@wordpress/block-editor": "^10.5.0", + "@wordpress/blocks": "^11.21.0", + "@wordpress/components": "^22.1.0", + "@wordpress/compose": "^5.20.0", + "@wordpress/data": "^7.6.0", + "@wordpress/dom-ready": "^3.22.0", + "@wordpress/edit-post": "^6.19.0", + "@wordpress/edit-site": "^4.19.0", + "@wordpress/editor": "^12.21.0", + "@wordpress/element": "^4.20.0", + "@wordpress/hooks": "^3.22.0", + "@wordpress/i18n": "^4.22.0", + "@wordpress/icons": "^9.13.0", + "@wordpress/is-shallow-equal": "^4.22.0", + "@wordpress/plugins": "^4.20.0", + "@wordpress/rich-text": "^5.20.0", + "@wordpress/url": "^3.23.0", "debug": "^4.3.3", "lodash": "^4.17.21", "react": "^17.0.2", @@ -53,7 +53,7 @@ "@automattic/calypso-apps-builder": "workspace:^", "@automattic/calypso-build": "workspace:^", "@automattic/calypso-eslint-overrides": "workspace:^", - "@wordpress/dependency-extraction-webpack-plugin": "^3.5.0", + "@wordpress/dependency-extraction-webpack-plugin": "^4.5.0", "jest": "^27.3.1", "npm-run-all": "^4.1.5", "postcss": "^8.4.5", diff --git a/client/blocks/import/ready/index.tsx b/client/blocks/import/ready/index.tsx index 4c8d9de4bdfd2..b2a13237ecf15 100644 --- a/client/blocks/import/ready/index.tsx +++ b/client/blocks/import/ready/index.tsx @@ -10,6 +10,7 @@ import { UrlData, GoToStep, RecordTracksEvent, ImporterPlatform } from '../types import { convertPlatformName, convertToFriendlyWebsiteName } from '../util'; import ImportPlatformDetails, { coveredPlatforms } from './platform-details'; import ImportPreview from './preview'; +import type { OnboardSelect } from '@automattic/data-stores'; import './style.scss'; /* eslint-disable wpcalypso/jsx-classname-namespace */ @@ -118,7 +119,10 @@ const ReadyNotStep: React.FunctionComponent< ReadyNotProps > = ( { recordTracksEvent, } ) => { const { __ } = useI18n(); - const goals = useSelect( ( select ) => select( ONBOARD_STORE ).getGoals() ); + const goals = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getGoals(), + [] + ); const { setGoals } = useDispatch( ONBOARD_STORE ); const recordReadyScreenEvent = () => { @@ -262,7 +266,10 @@ const ReadyAlreadyOnWPCOMStep: React.FunctionComponent< ReadyWpComProps > = ( { recordTracksEvent, } ) => { const { __ } = useI18n(); - const goals = useSelect( ( select ) => select( ONBOARD_STORE ).getGoals() ); + const goals = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getGoals(), + [] + ); const { setGoals } = useDispatch( ONBOARD_STORE ); const recordReadyScreenEvent = () => { diff --git a/client/blocks/importer/wordpress/index.tsx b/client/blocks/importer/wordpress/index.tsx index 61c1b7e5e290c..bb7b5f8cb8fc5 100644 --- a/client/blocks/importer/wordpress/index.tsx +++ b/client/blocks/importer/wordpress/index.tsx @@ -21,6 +21,7 @@ import ImportContentOnly from './import-content-only'; import ImportEverything from './import-everything'; import { WPImportOption } from './types'; import { storeMigrateSource, retrieveMigrateSource } from './utils'; +import type { OnboardSelect } from '@automattic/data-stores'; import './style.scss'; @@ -55,7 +56,10 @@ export const WordpressImporter: React.FunctionComponent< Props > = ( props ) => const hasAllSitesFetched = useSelector( ( state ) => hasAllSitesList( state ) ); const fromSiteAnalyzedData = useSelector( getUrlData ); const { setIsMigrateFromWp } = useDispatch( ONBOARD_STORE ); - const isMigrateFromWp = useSelect( ( select ) => select( ONBOARD_STORE ).getIsMigrateFromWp() ); + const isMigrateFromWp = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getIsMigrateFromWp(), + [] + ); /** ↓ Effects diff --git a/client/blocks/time-mismatch-warning/test/index.jsx b/client/blocks/time-mismatch-warning/test/index.jsx index e9615506a3618..dcdb704acbae4 100644 --- a/client/blocks/time-mismatch-warning/test/index.jsx +++ b/client/blocks/time-mismatch-warning/test/index.jsx @@ -26,11 +26,7 @@ jest.mock( 'calypso/state/preferences/selectors', () => ( { describe( 'TimeMismatchWarning', () => { beforeAll( () => { - jest.spyOn( global, 'Date' ).mockImplementation( () => ( { getTimezoneOffset: () => 240 } ) ); - } ); - - afterAll( () => { - jest.spyOn( global, 'Date' ).mockRestore(); + jest.spyOn( global.Date.prototype, 'getTimezoneOffset' ).mockImplementation( () => 240 ); } ); test( 'to render nothing if no site ID is provided', () => { diff --git a/client/components/inline-support-link/index.jsx b/client/components/inline-support-link/index.jsx index b97bda6d3fe8d..a4fb93718da01 100644 --- a/client/components/inline-support-link/index.jsx +++ b/client/components/inline-support-link/index.jsx @@ -1,6 +1,5 @@ import { Gridicon } from '@automattic/components'; import { localizeUrl } from '@automattic/i18n-utils'; -import { compose } from '@wordpress/compose'; import classnames from 'classnames'; import { localize } from 'i18n-calypso'; import PropTypes from 'prop-types'; @@ -164,8 +163,7 @@ const mapDispatchToProps = ( dispatch, ownProps ) => { }; }; -export default compose( - connect( null, mapDispatchToProps ), - localize, - withRouteModal( 'support-article' ) -)( InlineSupportLink ); +export default connect( + null, + mapDispatchToProps +)( localize( withRouteModal( 'support-article' )( InlineSupportLink ) ) ); diff --git a/client/jetpack-cloud/sections/agency-dashboard/sites-overview/site-card/test/site-card.tsx b/client/jetpack-cloud/sections/agency-dashboard/sites-overview/site-card/test/site-card.tsx index e437728e188ee..6d7bdfe39c2af 100644 --- a/client/jetpack-cloud/sections/agency-dashboard/sites-overview/site-card/test/site-card.tsx +++ b/client/jetpack-cloud/sections/agency-dashboard/sites-overview/site-card/test/site-card.tsx @@ -12,6 +12,18 @@ import SiteCard from '../index'; import type { SiteData } from '../../types'; describe( '', () => { + beforeAll( () => { + window.matchMedia = jest.fn().mockImplementation( ( query ) => { + return { + matches: true, + media: query, + onchange: null, + addListener: jest.fn(), + removeListener: jest.fn(), + }; + } ); + } ); + nock( 'https://public-api.wordpress.com' ) .persist() .get( '/rest/v1.1/jetpack-blogs/1234/test-connection?is_stale_connection_healthy=true' ) diff --git a/client/jetpack-cloud/sections/agency-dashboard/sites-overview/site-table-row/test/site-table-row.tsx b/client/jetpack-cloud/sections/agency-dashboard/sites-overview/site-table-row/test/site-table-row.tsx index 12b61e6873247..a1f0954e0c643 100644 --- a/client/jetpack-cloud/sections/agency-dashboard/sites-overview/site-table-row/test/site-table-row.tsx +++ b/client/jetpack-cloud/sections/agency-dashboard/sites-overview/site-table-row/test/site-table-row.tsx @@ -13,6 +13,18 @@ import SiteTableRow from '../index'; import type { SiteData } from '../../types'; describe( '', () => { + beforeAll( () => { + window.matchMedia = jest.fn().mockImplementation( ( query ) => { + return { + matches: true, + media: query, + onchange: null, + addListener: jest.fn(), + removeListener: jest.fn(), + }; + } ); + } ); + nock( 'https://public-api.wordpress.com' ) .persist() .get( '/rest/v1.1/jetpack-blogs/1234/test-connection?is_stale_connection_healthy=true' ) @@ -91,19 +103,19 @@ describe( '', () => { const store = mockStore( initialState ); const queryClient = new QueryClient(); - const { getByText } = render( - - - - - - -
-
-
- ); - test( 'should render correctly and have the error message and the link to fix the issue', async () => { + const { getByText } = render( + + + + + + +
+
+
+ ); + await waitFor( () => { expect( getByText( 'Jetpack is unable to connect to this site' ) ).toBeVisible(); expect( getByText( /fix now/i ) ).toBeVisible(); diff --git a/client/jetpack-cloud/sections/agency-dashboard/sites-overview/site-table/test/site-table.tsx b/client/jetpack-cloud/sections/agency-dashboard/sites-overview/site-table/test/site-table.tsx index 617eea59337dd..db9424ddb2d31 100644 --- a/client/jetpack-cloud/sections/agency-dashboard/sites-overview/site-table/test/site-table.tsx +++ b/client/jetpack-cloud/sections/agency-dashboard/sites-overview/site-table/test/site-table.tsx @@ -14,6 +14,18 @@ import SiteTable from '../index'; import type { SiteData } from '../../types'; describe( '', () => { + beforeAll( () => { + window.matchMedia = jest.fn().mockImplementation( ( query ) => { + return { + matches: true, + media: query, + onchange: null, + addListener: jest.fn(), + removeListener: jest.fn(), + }; + } ); + } ); + nock( 'https://public-api.wordpress.com' ) .persist() .get( '/rest/v1.1/jetpack-blogs/1234/test-connection?is_stale_connection_healthy=true' ) @@ -96,15 +108,15 @@ describe( '', () => { const store = mockStore( initialState ); const queryClient = new QueryClient(); - const { getByTestId } = render( - - - - - - ); - test( 'should render correctly and have href and status for each row', () => { + const { getByTestId } = render( + + + + + + ); + const backupEle = getByTestId( `row-${ blogId }-backup` ); expect( backupEle.getAttribute( 'href' ) ).toEqual( `/backup/${ siteUrl }` ); expect( backupEle.getElementsByClassName( 'sites-overview__badge' )[ 0 ].textContent ).toEqual( diff --git a/client/jetpack-cloud/sections/partner-portal/credit-card-fields/credit-card-element-field.tsx b/client/jetpack-cloud/sections/partner-portal/credit-card-fields/credit-card-element-field.tsx index ecfb15901b077..ea1ef15d9d693 100644 --- a/client/jetpack-cloud/sections/partner-portal/credit-card-fields/credit-card-element-field.tsx +++ b/client/jetpack-cloud/sections/partner-portal/credit-card-fields/credit-card-element-field.tsx @@ -4,6 +4,7 @@ import { useSelect } from '@wordpress/data'; import { useI18n } from '@wordpress/react-i18n'; import classnames from 'classnames'; import type { StripeElementChangeEvent, StripeElementStyle } from '@stripe/stripe-js'; +import type { CreditCardSelectors } from 'calypso/state/partner-portal/types'; export default function CreditCardElementField( { setIsStripeFullyLoaded, @@ -17,8 +18,9 @@ export default function CreditCardElementField( { const { __ } = useI18n(); const { formStatus } = useFormStatus(); const isDisabled = formStatus !== FormStatus.READY; - const { card: cardError } = useSelect( ( select ) => - select( 'credit-card' ).getCardDataErrors() + const { card: cardError } = useSelect( + ( select ) => ( select( 'credit-card' ) as CreditCardSelectors ).getCardDataErrors(), + [] ); return ( diff --git a/client/jetpack-cloud/sections/partner-portal/credit-card-fields/credit-card-submit-button.tsx b/client/jetpack-cloud/sections/partner-portal/credit-card-fields/credit-card-submit-button.tsx index 755f39aed0b4e..db222c4133062 100644 --- a/client/jetpack-cloud/sections/partner-portal/credit-card-fields/credit-card-submit-button.tsx +++ b/client/jetpack-cloud/sections/partner-portal/credit-card-fields/credit-card-submit-button.tsx @@ -6,9 +6,11 @@ import debugFactory from 'debug'; import { useMemo } from 'react'; import type { StripeConfiguration } from '@automattic/calypso-stripe'; import type { ProcessPayment } from '@automattic/composite-checkout'; +import type { StoreState } from '@automattic/wpcom-checkout'; import type { Stripe } from '@stripe/stripe-js'; import type { I18n } from '@wordpress/i18n'; import type { State } from 'calypso/state/partner-portal/credit-card-form/reducer'; +import type { CreditCardSelectors } from 'calypso/state/partner-portal/types'; const debug = debugFactory( 'calypso:partner-portal:credit-card' ); @@ -28,9 +30,13 @@ export default function CreditCardSubmitButton( { activeButtonText: string | undefined; } ) { const { __ } = useI18n(); - const fields = useSelect( ( select ) => select( 'credit-card' ).getFields() ); - const useAsPrimaryPaymentMethod = useSelect( ( select ) => - select( 'credit-card' ).useAsPrimaryPaymentMethod() + const fields: StoreState< string > = useSelect( + ( select ) => ( select( 'credit-card' ) as CreditCardSelectors ).getFields(), + [] + ); + const useAsPrimaryPaymentMethod: boolean = useSelect( + ( select ) => ( select( 'credit-card' ) as CreditCardSelectors ).useAsPrimaryPaymentMethod(), + [] ); const cardholderName = fields.cardholderName; const { formStatus } = useFormStatus(); diff --git a/client/jetpack-cloud/sections/partner-portal/credit-card-fields/index.tsx b/client/jetpack-cloud/sections/partner-portal/credit-card-fields/index.tsx index 7314911f15b17..ad520178ee92d 100644 --- a/client/jetpack-cloud/sections/partner-portal/credit-card-fields/index.tsx +++ b/client/jetpack-cloud/sections/partner-portal/credit-card-fields/index.tsx @@ -10,16 +10,21 @@ import { recordTracksEvent } from 'calypso/state/analytics/actions'; import CreditCardElementField from './credit-card-element-field'; import CreditCardLoading from './credit-card-loading'; import SetAsPrimaryPaymentMethod from './set-as-primary-payment-method'; +import type { StoreState } from '@automattic/wpcom-checkout'; import type { StripeElementChangeEvent, StripeElementStyle } from '@stripe/stripe-js'; - +import type { CreditCardSelectors } from 'calypso/state/partner-portal/types'; import './style.scss'; export default function CreditCardFields() { const { __ } = useI18n(); const [ isStripeFullyLoaded, setIsStripeFullyLoaded ] = useState( false ); - const fields = useSelect( ( select ) => select( 'credit-card' ).getFields() ); - const useAsPrimaryPaymentMethod = useSelect( ( select ) => - select( 'credit-card' ).useAsPrimaryPaymentMethod() + const fields: StoreState< string > = useSelect( + ( select ) => ( select( 'credit-card' ) as CreditCardSelectors ).getFields(), + [] + ); + const useAsPrimaryPaymentMethod: boolean = useSelect( + ( select ) => ( select( 'credit-card' ) as CreditCardSelectors ).useAsPrimaryPaymentMethod(), + [] ); const getField = ( key: string | number ) => fields[ key ] || {}; const getErrorMessagesForField = ( key: string | number ) => { diff --git a/client/jetpack-cloud/sections/partner-portal/primary/payment-method-add/index.tsx b/client/jetpack-cloud/sections/partner-portal/primary/payment-method-add/index.tsx index eeee349b2d132..14433eaf6a2a3 100644 --- a/client/jetpack-cloud/sections/partner-portal/primary/payment-method-add/index.tsx +++ b/client/jetpack-cloud/sections/partner-portal/primary/payment-method-add/index.tsx @@ -38,6 +38,7 @@ import { doesPartnerRequireAPaymentMethod } from 'calypso/state/partner-portal/p import { fetchStoredCards } from 'calypso/state/partner-portal/stored-cards/actions'; import getSites from 'calypso/state/selectors/get-sites'; import type { SiteDetails } from '@automattic/data-stores'; +import type { CreditCardSelectors } from 'calypso/state/partner-portal/types'; import './style.scss'; @@ -61,8 +62,9 @@ function PaymentMethodAdd( { selectedSite }: { selectedSite?: SiteDetails | null () => [ stripeMethod ].filter( isValueTruthy ), [ stripeMethod ] ); - const useAsPrimaryPaymentMethod = useSelect( ( select ) => - select( 'credit-card' ).useAsPrimaryPaymentMethod() + const useAsPrimaryPaymentMethod: boolean = useSelect( + ( select ) => ( select( 'credit-card' ) as CreditCardSelectors ).useAsPrimaryPaymentMethod(), + [] ); const sites = useSelector( getSites ); diff --git a/client/landing/gutenboarding/components/domain-picker-button/index.tsx b/client/landing/gutenboarding/components/domain-picker-button/index.tsx index 52f8af440522b..172542f5d69a8 100644 --- a/client/landing/gutenboarding/components/domain-picker-button/index.tsx +++ b/client/landing/gutenboarding/components/domain-picker-button/index.tsx @@ -8,6 +8,7 @@ import { usePath, Step } from '../../path'; import { DOMAIN_SUGGESTIONS_STORE } from '../../stores/domain-suggestions'; import { ONBOARD_STORE } from '../../stores/onboard'; import Link from '../link'; +import type { DomainSuggestionsSelect, OnboardSelect } from '@automattic/data-stores'; import type { FunctionComponent } from 'react'; import './style.scss'; @@ -16,8 +17,9 @@ const DomainPickerButton: FunctionComponent = () => { const { __ } = useI18n(); const locale = useLocale(); const makePath = usePath(); - const { domain, selectedDesign, siteTitle } = useSelect( ( select ) => - select( ONBOARD_STORE ).getState() + const { domain, selectedDesign, siteTitle } = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getState(), + [] ); // Use site title as search query for a domain suggestion @@ -30,13 +32,16 @@ const DomainPickerButton: FunctionComponent = () => { if ( domain || ! isValidQuery ) { return; } - return select( DOMAIN_SUGGESTIONS_STORE ).getDomainSuggestions( suggestionQuery, { - // Avoid `only_wordpressdotcom` — it seems to fail to find results sometimes - include_wordpressdotcom: false, - include_dotblogsubdomain: false, - quantity: 1, // this will give the recommended domain only - locale, - } ); + return ( select( DOMAIN_SUGGESTIONS_STORE ) as DomainSuggestionsSelect ).getDomainSuggestions( + suggestionQuery, + { + // Avoid `only_wordpressdotcom` — it seems to fail to find results sometimes + include_wordpressdotcom: false, + include_dotblogsubdomain: false, + quantity: 1, // this will give the recommended domain only + locale, + } + ); }, [ suggestionQuery ] )?.[ 0 ]; diff --git a/client/landing/gutenboarding/components/header/index.tsx b/client/landing/gutenboarding/components/header/index.tsx index 77a1febec2738..3cd6a519ec719 100644 --- a/client/landing/gutenboarding/components/header/index.tsx +++ b/client/landing/gutenboarding/components/header/index.tsx @@ -8,6 +8,7 @@ import { ONBOARD_STORE } from '../../stores/onboard'; import DomainPickerButton from '../domain-picker-button'; import Link from '../link'; import PlansButton from '../plans-button'; +import type { OnboardSelect } from '@automattic/data-stores'; import type { FunctionComponent } from 'react'; import './style.scss'; @@ -19,7 +20,10 @@ const Header: FunctionComponent = () => { const isAnchorFmSignup = useIsAnchorFm(); const makePath = usePath(); - const { siteTitle } = useSelect( ( select ) => select( ONBOARD_STORE ).getState() ); + const { siteTitle } = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getState(), + [] + ); // steps (including modals) where we show Domains button const showDomainsButton = diff --git a/client/landing/gutenboarding/components/signup-form/index.tsx b/client/landing/gutenboarding/components/signup-form/index.tsx index 500cb39cfff6b..95351632cb228 100644 --- a/client/landing/gutenboarding/components/signup-form/index.tsx +++ b/client/landing/gutenboarding/components/signup-form/index.tsx @@ -25,6 +25,7 @@ import { USER_STORE } from '../../stores/user'; import './style.scss'; import SignupAnchorLayout from './signup-anchor-layout'; import SignupDefaultLayout from './signup-default-layout'; +import type { OnboardSelect, UserSelect } from '@automattic/data-stores'; import type { FormEvent } from 'react'; interface Props { @@ -37,9 +38,18 @@ const SignupForm = ( { onRequestClose }: Props ) => { const [ passwordVal, setPasswordVal ] = useState( '' ); const [ recaptchaClientId, setRecaptchaClientId ] = useState< number >(); const { createAccount, clearErrors } = useDispatch( USER_STORE ); - const isFetchingNewUser = useSelect( ( select ) => select( USER_STORE ).isFetchingNewUser() ); - const newUserError = useSelect( ( select ) => select( USER_STORE ).getNewUserError() ); - const { siteTitle } = useSelect( ( select ) => select( ONBOARD_STORE ) ).getState(); + const isFetchingNewUser = useSelect( + ( select ) => ( select( USER_STORE ) as UserSelect ).isFetchingNewUser(), + [] + ); + const newUserError = useSelect( + ( select ) => ( select( USER_STORE ) as UserSelect ).getNewUserError(), + [] + ); + const { siteTitle } = useSelect( + ( select ) => select( ONBOARD_STORE ) as OnboardSelect, + [] + ).getState(); const langParam = useLangRouteParam(); const makePath = usePath(); const currentStep = useCurrentStep(); diff --git a/client/landing/gutenboarding/hooks/use-detect-matching-anchor-site.ts b/client/landing/gutenboarding/hooks/use-detect-matching-anchor-site.ts index f5360c96d4f89..ca16933ea7aea 100644 --- a/client/landing/gutenboarding/hooks/use-detect-matching-anchor-site.ts +++ b/client/landing/gutenboarding/hooks/use-detect-matching-anchor-site.ts @@ -3,6 +3,7 @@ import { useState, useEffect } from 'react'; import wpcom from 'calypso/lib/wp'; import { useIsAnchorFm, useAnchorFmParams } from '../path'; import { USER_STORE } from '../stores/user'; +import type { UserSelect } from '@automattic/data-stores'; interface AnchorEndpointResult { location: string | false; @@ -22,7 +23,10 @@ export default function useDetectMatchingAnchorSite(): boolean { anchorFmIsNewSite, } = useAnchorFmParams(); const isAnchorFm = useIsAnchorFm(); - const currentUserExists = useSelect( ( select ) => !! select( USER_STORE ).getCurrentUser() ); + const currentUserExists = useSelect( + ( select ) => !! ( select( USER_STORE ) as UserSelect ).getCurrentUser(), + [] + ); const [ isLoading, setIsLoading ] = useState( !! ( isAnchorFm && currentUserExists ) ); useEffect( () => { diff --git a/client/landing/gutenboarding/hooks/use-free-domain-suggestion.ts b/client/landing/gutenboarding/hooks/use-free-domain-suggestion.ts index ef1f830567b4c..89256d5e60cc6 100644 --- a/client/landing/gutenboarding/hooks/use-free-domain-suggestion.ts +++ b/client/landing/gutenboarding/hooks/use-free-domain-suggestion.ts @@ -1,20 +1,27 @@ import { useSelect } from '@wordpress/data'; import { DOMAIN_SUGGESTIONS_STORE } from '../stores/domain-suggestions'; import { ONBOARD_STORE } from '../stores/onboard'; +import type { DomainSuggestionsSelect, OnboardSelect } from '@automattic/data-stores'; export function useFreeDomainSuggestion() { - const domainSearch = useSelect( ( select ) => select( ONBOARD_STORE ).getDomainSearch() ); + const domainSearch = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getDomainSearch(), + [] + ); return useSelect( ( select ) => { if ( ! domainSearch ) { return; } - return select( DOMAIN_SUGGESTIONS_STORE ).getDomainSuggestions( domainSearch, { - // Avoid `only_wordpressdotcom` — it seems to fail to find results sometimes - include_wordpressdotcom: true, - quantity: 1, - } )?.[ 0 ]; + return ( select( DOMAIN_SUGGESTIONS_STORE ) as DomainSuggestionsSelect ).getDomainSuggestions( + domainSearch, + { + // Avoid `only_wordpressdotcom` — it seems to fail to find results sometimes + include_wordpressdotcom: true, + quantity: 1, + } + )?.[ 0 ]; }, [ domainSearch ] ); diff --git a/client/landing/gutenboarding/hooks/use-last-location.ts b/client/landing/gutenboarding/hooks/use-last-location.ts index 7bf05463bade1..c6c67f98275d0 100644 --- a/client/landing/gutenboarding/hooks/use-last-location.ts +++ b/client/landing/gutenboarding/hooks/use-last-location.ts @@ -1,11 +1,15 @@ import { useSelect } from '@wordpress/data'; import { useHistory } from 'react-router-dom'; import { ONBOARD_STORE } from '../stores/onboard'; +import type { OnboardSelect } from '@automattic/data-stores'; export default function useLastLocation(): { goLastLocation: () => void } { const history = useHistory(); - const lastLocation = useSelect( ( select ) => select( ONBOARD_STORE ).getLastLocation(), [] ); + const lastLocation = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getLastLocation(), + [] + ); const goLastLocation = ( fallbackLocation = '/' ) => { history.push( lastLocation || fallbackLocation ); diff --git a/client/landing/gutenboarding/hooks/use-on-login.ts b/client/landing/gutenboarding/hooks/use-on-login.ts index 0c14821182b71..338ed474f2987 100644 --- a/client/landing/gutenboarding/hooks/use-on-login.ts +++ b/client/landing/gutenboarding/hooks/use-on-login.ts @@ -6,6 +6,7 @@ import { ONBOARD_STORE } from '../stores/onboard'; import { SITE_STORE } from '../stores/site'; import { USER_STORE } from '../stores/user'; import { useNewSiteVisibility } from './use-selected-plan'; +import type { SiteSelect, UserSelect } from '@automattic/data-stores'; /** * After signup a site is automatically created using the username and bearerToken @@ -14,9 +15,18 @@ import { useNewSiteVisibility } from './use-selected-plan'; export default function useOnLogin(): void { const locale = useLocale(); const { createSite } = useDispatch( ONBOARD_STORE ); - const currentUser = useSelect( ( select ) => select( USER_STORE ).getCurrentUser() ); - const isCreatingSite = useSelect( ( select ) => select( SITE_STORE ).isFetchingSite() ); - const newSite = useSelect( ( select ) => select( SITE_STORE ).getNewSite() ); + const currentUser = useSelect( + ( select ) => ( select( USER_STORE ) as UserSelect ).getCurrentUser(), + [] + ); + const isCreatingSite = useSelect( + ( select ) => ( select( SITE_STORE ) as SiteSelect ).isFetchingSite(), + [] + ); + const newSite = useSelect( + ( select ) => ( select( SITE_STORE ) as SiteSelect ).getNewSite(), + [] + ); const shouldTriggerCreate = useNewQueryParam(); const visibility = useNewSiteVisibility(); diff --git a/client/landing/gutenboarding/hooks/use-on-signup.ts b/client/landing/gutenboarding/hooks/use-on-signup.ts index 64458c7e08f24..90ee1a7cf531a 100644 --- a/client/landing/gutenboarding/hooks/use-on-signup.ts +++ b/client/landing/gutenboarding/hooks/use-on-signup.ts @@ -6,6 +6,7 @@ import { ONBOARD_STORE } from '../stores/onboard'; import { SITE_STORE } from '../stores/site'; import { USER_STORE } from '../stores/user'; import { useNewSiteVisibility } from './use-selected-plan'; +import type { SiteSelect, UserSelect } from '@automattic/data-stores'; /** * After signup a site is automatically created using the username and bearerToken @@ -15,8 +16,14 @@ export default function useOnSignup(): void { const locale = useLocale(); const { createSite } = useDispatch( ONBOARD_STORE ); - const newUser = useSelect( ( select ) => select( USER_STORE ).getNewUser() ); - const newSite = useSelect( ( select ) => select( SITE_STORE ).getNewSite() ); + const newUser = useSelect( + ( select ) => ( select( USER_STORE ) as UserSelect ).getNewUser(), + [] + ); + const newSite = useSelect( + ( select ) => ( select( SITE_STORE ) as SiteSelect ).getNewSite(), + [] + ); const visibility = useNewSiteVisibility(); const isAnchorFmSignup = useIsAnchorFm(); const { anchorFmPodcastId, anchorFmEpisodeId, anchorFmSpotifyUrl } = useAnchorFmParams(); diff --git a/client/landing/gutenboarding/hooks/use-on-site-creation.ts b/client/landing/gutenboarding/hooks/use-on-site-creation.ts index 40cc79828ef44..0d6c29286051c 100644 --- a/client/landing/gutenboarding/hooks/use-on-site-creation.ts +++ b/client/landing/gutenboarding/hooks/use-on-site-creation.ts @@ -9,6 +9,7 @@ import { PLANS_STORE } from '../stores/plans'; import { SITE_STORE } from '../stores/site'; import { USER_STORE } from '../stores/user'; import { useSelectedPlan, useShouldRedirectToEditorAfterCheckout } from './use-selected-plan'; +import type { PlansSelect, OnboardSelect, SiteSelect, UserSelect } from '@automattic/data-stores'; /** * After a new site has been created there are 3 scenarios to cover: @@ -18,18 +19,36 @@ import { useSelectedPlan, useShouldRedirectToEditorAfterCheckout } from './use-s */ export default function useOnSiteCreation(): void { - const { domain } = useSelect( ( select ) => select( ONBOARD_STORE ).getState() ); - const isRedirecting = useSelect( ( select ) => select( ONBOARD_STORE ).getIsRedirecting() ); - const newSite = useSelect( ( select ) => select( SITE_STORE ).getNewSite() ); - const newUser = useSelect( ( select ) => select( USER_STORE ).getNewUser() ); + const { domain } = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getState(), + [] + ); + const isRedirecting = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getIsRedirecting(), + [] + ); + const newSite = useSelect( + ( select ) => ( select( SITE_STORE ) as SiteSelect ).getNewSite(), + [] + ); + const newUser = useSelect( + ( select ) => ( select( USER_STORE ) as UserSelect ).getNewUser(), + [] + ); const selectedPlan = useSelectedPlan(); const shouldRedirectToEditorAfterCheckout = useShouldRedirectToEditorAfterCheckout(); - const design = useSelect( ( select ) => select( ONBOARD_STORE ).getSelectedDesign() ); - const selectedPlanProductId = useSelect( ( select ) => - select( ONBOARD_STORE ).getPlanProductId() + const design = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedDesign(), + [] + ); + const selectedPlanProductId = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getPlanProductId(), + [] ); - const planProductSource = useSelect( ( select ) => - select( PLANS_STORE ).getPlanProductById( selectedPlanProductId ) + const planProductSource = useSelect( + ( select ) => + ( select( PLANS_STORE ) as PlansSelect ).getPlanProductById( selectedPlanProductId ), + [ selectedPlanProductId ] ); const flow = useOnboardingFlow(); diff --git a/client/landing/gutenboarding/hooks/use-selected-plan.ts b/client/landing/gutenboarding/hooks/use-selected-plan.ts index d6242a8013b67..5ad851d0045f3 100644 --- a/client/landing/gutenboarding/hooks/use-selected-plan.ts +++ b/client/landing/gutenboarding/hooks/use-selected-plan.ts @@ -6,23 +6,27 @@ import { ONBOARD_STORE } from '../stores/onboard'; import { PLANS_STORE } from '../stores/plans'; import { WPCOM_FEATURES_STORE } from '../stores/wpcom-features'; import type { Plan } from '../stores/plans'; +import type { PlansSelect, OnboardSelect, WpcomFeaturesSelect } from '@automattic/data-stores'; /** * A React hook that returns the WordPress.com plan from path. * * Exception: Free plan is not returned while features are selected * - * @returns { Plan } An object describing a WordPress.com plan + * @returns { Plan|undefined } An object describing a WordPress.com plan */ export function usePlanFromPath(): Plan | undefined { const planPath = usePlanRouteParam(); const locale = useLocale(); - const [ isPlanFree, planFromPath, selectedFeatures ] = useSelect( ( select ) => [ - select( PLANS_STORE ).isPlanFree, - select( PLANS_STORE ).getPlanByPath( planPath, locale ), - select( ONBOARD_STORE ).getSelectedFeatures(), - ] ); + const { isPlanFree, planFromPath, selectedFeatures } = useSelect( + ( select ) => ( { + isPlanFree: ( select( PLANS_STORE ) as PlansSelect ).isPlanFree, + planFromPath: ( select( PLANS_STORE ) as PlansSelect ).getPlanByPath( planPath, locale ), + selectedFeatures: ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedFeatures(), + } ), + [ planPath, locale ] + ); // don't return Free plan if any feature is currently selected if ( isPlanFree( planFromPath?.periodAgnosticSlug ) && selectedFeatures.length ) { @@ -35,23 +39,41 @@ export function usePlanFromPath(): Plan | undefined { export function useSelectedPlan(): Plan | undefined { const locale = useLocale(); // Pre-load the plans details to ensure the plans are fetched early from the API endpoint. - useSelect( ( select ) => select( PLANS_STORE ).getSupportedPlans( locale ) ); + useSelect( + ( select ) => ( select( PLANS_STORE ) as PlansSelect ).getSupportedPlans( locale ), + [ locale ] + ); - const selectedFeatures = useSelect( ( select ) => select( ONBOARD_STORE ).getSelectedFeatures() ); - const selectedPlanProductId = useSelect( ( select ) => - select( ONBOARD_STORE ).getPlanProductId() + const selectedFeatures = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedFeatures(), + [] + ); + const selectedPlanProductId = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getPlanProductId(), + [] ); - const recommendedPlanSlug = useSelect( ( select ) => - select( WPCOM_FEATURES_STORE ).getRecommendedPlanSlug( selectedFeatures ) + const recommendedPlanSlug = useSelect( + ( select ) => + ( select( WPCOM_FEATURES_STORE ) as WpcomFeaturesSelect ).getRecommendedPlanSlug( + selectedFeatures + ), + [ selectedFeatures ] ); - const recommendedPlan = useSelect( ( select ) => - select( PLANS_STORE ).getPlanByPeriodAgnosticSlug( recommendedPlanSlug, locale ) + const recommendedPlan = useSelect( + ( select ) => + ( select( PLANS_STORE ) as PlansSelect ).getPlanByPeriodAgnosticSlug( + recommendedPlanSlug, + locale + ), + [ recommendedPlanSlug, locale ] ); - const selectedPlan = useSelect( ( select ) => - select( PLANS_STORE ).getPlanByProductId( selectedPlanProductId, locale ) + const selectedPlan = useSelect( + ( select ) => + ( select( PLANS_STORE ) as PlansSelect ).getPlanByProductId( selectedPlanProductId, locale ), + [ selectedPlanProductId, locale ] ); const planFromPath = usePlanFromPath(); @@ -73,5 +95,8 @@ export function useShouldRedirectToEditorAfterCheckout(): boolean { // The ecommerce plan follows another flow, so we shouldn't interrupt // it by trying to redirect to the editor. const currentSlug = useSelectedPlan()?.periodAgnosticSlug; - return ! useSelect( ( select ) => select( PLANS_STORE ).isPlanEcommerce( currentSlug ) ); + return ! useSelect( + ( select ) => ( select( PLANS_STORE ) as PlansSelect ).isPlanEcommerce( currentSlug ), + [ currentSlug ] + ); } diff --git a/client/landing/gutenboarding/hooks/use-signup.ts b/client/landing/gutenboarding/hooks/use-signup.ts index 5a9503ac94be4..bd61803e9ef1c 100644 --- a/client/landing/gutenboarding/hooks/use-signup.ts +++ b/client/landing/gutenboarding/hooks/use-signup.ts @@ -4,6 +4,7 @@ import { useHistory } from 'react-router-dom'; import { useIsAnchorFm } from '../path'; import { ONBOARD_STORE } from '../stores/onboard'; import { USER_STORE } from '../stores/user'; +import type { OnboardSelect, UserSelect } from '@automattic/data-stores'; /** * When a new user completes Gutenboarding, before creating a site we show signup dialog. @@ -17,11 +18,20 @@ import { USER_STORE } from '../stores/user'; */ export default function useSignup() { - const { showSignupDialog } = useSelect( ( select ) => select( ONBOARD_STORE ).getState() ); + const { showSignupDialog } = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getState(), + [] + ); const { setShowSignupDialog } = useDispatch( ONBOARD_STORE ); const isAnchorFmSignup = useIsAnchorFm(); - const hasNewUser = useSelect( ( select ) => !! select( USER_STORE ).getNewUser() ); - const hasCurrentUser = useSelect( ( select ) => !! select( USER_STORE ).getCurrentUser() ); + const hasNewUser = useSelect( + ( select ) => !! ( select( USER_STORE ) as UserSelect ).getNewUser(), + [] + ); + const hasCurrentUser = useSelect( + ( select ) => !! ( select( USER_STORE ) as UserSelect ).getCurrentUser(), + [] + ); const { location: { pathname, search }, diff --git a/client/landing/gutenboarding/hooks/use-site-title.ts b/client/landing/gutenboarding/hooks/use-site-title.ts index 2bd870a963034..c17f501726243 100644 --- a/client/landing/gutenboarding/hooks/use-site-title.ts +++ b/client/landing/gutenboarding/hooks/use-site-title.ts @@ -4,13 +4,17 @@ import { useLocation } from 'react-router-dom'; import { isAnchorPodcastIdValid } from '../path'; import { ONBOARD_STORE } from '../stores/onboard'; import usePodcastTitle from './use-podcast-title'; +import type { OnboardSelect } from '@automattic/data-stores'; export default function useSiteTitle(): void { const { setSiteTitle } = useDispatch( ONBOARD_STORE ); const podcastTitle = usePodcastTitle(); - const { hasSiteTitle } = useSelect( ( select ) => ( { - hasSiteTitle: select( ONBOARD_STORE ).getSelectedSiteTitle().length > 0, - } ) ); + const { hasSiteTitle } = useSelect( + ( select ) => ( { + hasSiteTitle: ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedSiteTitle().length > 0, + } ), + [] + ); // When first loading a url including an ?anchor_podcast query param, clear // the title. diff --git a/client/landing/gutenboarding/hooks/use-step-navigation.ts b/client/landing/gutenboarding/hooks/use-step-navigation.ts index edc9e95531727..cfc25d9a0e791 100644 --- a/client/landing/gutenboarding/hooks/use-step-navigation.ts +++ b/client/landing/gutenboarding/hooks/use-step-navigation.ts @@ -7,6 +7,7 @@ import { USER_STORE } from '../stores/user'; import { useNewSiteVisibility } from './use-selected-plan'; import useSignup from './use-signup'; import useSteps from './use-steps'; +import type { UserSelect } from '@automattic/data-stores'; /** * A React hook that returns callback to navigate to previous and next steps in Gutenboarding flow @@ -25,8 +26,14 @@ export default function useStepNavigation(): { goBack: () => void; goNext: () => const steps = useSteps(); // @TODO: move site creation to a separate hook or an action on the ONBOARD store - const currentUser = useSelect( ( select ) => select( USER_STORE ).getCurrentUser() ); - const newUser = useSelect( ( select ) => select( USER_STORE ).getNewUser() ); + const currentUser = useSelect( + ( select ) => ( select( USER_STORE ) as UserSelect ).getCurrentUser(), + [] + ); + const newUser = useSelect( + ( select ) => ( select( USER_STORE ) as UserSelect ).getNewUser(), + [] + ); const { anchorFmPodcastId, anchorFmEpisodeId, anchorFmSpotifyUrl } = useAnchorFmParams(); const { createSite } = useDispatch( ONBOARD_STORE ); diff --git a/client/landing/gutenboarding/hooks/use-steps.ts b/client/landing/gutenboarding/hooks/use-steps.ts index 345e33b420314..82bbdf19f2d19 100644 --- a/client/landing/gutenboarding/hooks/use-steps.ts +++ b/client/landing/gutenboarding/hooks/use-steps.ts @@ -4,12 +4,13 @@ import { Step, StepType, useIsAnchorFm } from '../path'; import { ONBOARD_STORE } from '../stores/onboard'; import { PLANS_STORE } from '../stores/plans'; import { usePlanFromPath } from './use-selected-plan'; +import type { PlansSelect, OnboardSelect } from '@automattic/data-stores'; export default function useSteps(): Array< StepType > { const locale = useLocale(); const { hasSiteTitle, hasSelectedDesignWithoutFonts } = useSelect( ( select ) => { - const onboardSelect = select( ONBOARD_STORE ); + const onboardSelect: OnboardSelect = select( ONBOARD_STORE ); return { hasSiteTitle: onboardSelect.hasSiteTitle(), hasSelectedDesignWithoutFonts: onboardSelect.hasSelectedDesignWithoutFonts(), @@ -52,12 +53,18 @@ export default function useSteps(): Array< StepType > { // Logic necessary to skip Domains or Plans steps // General rule: if a step has been used already, don't remove it. - const { domain, hasUsedDomainsStep, hasUsedPlansStep } = useSelect( ( select ) => - select( ONBOARD_STORE ).getState() + const { domain, hasUsedDomainsStep, hasUsedPlansStep } = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getState(), + [] ); - const planProductId = useSelect( ( select ) => select( ONBOARD_STORE ).getPlanProductId() ); - const plan = useSelect( ( select ) => - select( PLANS_STORE ).getPlanByProductId( planProductId, locale ) + const planProductId = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getPlanProductId(), + [] + ); + const plan = useSelect( + ( select ) => + ( select( PLANS_STORE ) as PlansSelect ).getPlanByProductId( planProductId, locale ), + [ planProductId, locale ] ); const hasPlanFromPath = !! usePlanFromPath(); diff --git a/client/landing/gutenboarding/hooks/use-track-onboarding-start.ts b/client/landing/gutenboarding/hooks/use-track-onboarding-start.ts index f24d6e47f15ec..bd4c2d0a5a938 100644 --- a/client/landing/gutenboarding/hooks/use-track-onboarding-start.ts +++ b/client/landing/gutenboarding/hooks/use-track-onboarding-start.ts @@ -4,14 +4,21 @@ import { recordOnboardingStart } from '../lib/analytics'; import { useOnboardingFlow } from '../path'; import { ONBOARD_STORE } from '../stores/onboard'; import { USER_STORE } from '../stores/user'; +import type { OnboardSelect, UserSelect } from '@automattic/data-stores'; /** * Records an event in tracks on starting the onboarding flow, after trying to get the current user */ export default function useTrackOnboardingStart() { - const currentUser = useSelect( ( select ) => select( USER_STORE ).getCurrentUser() ); - const { hasOnboardingStarted } = useSelect( ( select ) => select( ONBOARD_STORE ).getState() ); + const currentUser = useSelect( + ( select ) => ( select( USER_STORE ) as UserSelect ).getCurrentUser(), + [] + ); + const { hasOnboardingStarted } = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getState(), + [] + ); const { startOnboarding } = useDispatch( ONBOARD_STORE ); const flow = useOnboardingFlow(); diff --git a/client/landing/gutenboarding/onboarding-block/acquire-intent/index.tsx b/client/landing/gutenboarding/onboarding-block/acquire-intent/index.tsx index dc61392ce3fdf..49ec30949892f 100644 --- a/client/landing/gutenboarding/onboarding-block/acquire-intent/index.tsx +++ b/client/landing/gutenboarding/onboarding-block/acquire-intent/index.tsx @@ -10,12 +10,16 @@ import { recordSiteTitleSkip } from '../../lib/analytics'; import { useIsAnchorFm } from '../../path'; import { ONBOARD_STORE } from '../../stores/onboard'; import SiteTitle from './site-title'; +import type { OnboardSelect } from '@automattic/data-stores'; import './style.scss'; const AcquireIntent: React.FunctionComponent = () => { const { __ } = useI18n(); - const { getSelectedSiteTitle, hasSiteTitle } = useSelect( ( select ) => select( ONBOARD_STORE ) ); + const { getSelectedSiteTitle, hasSiteTitle } = useSelect( + ( select ) => select( ONBOARD_STORE ) as OnboardSelect, + [] + ); const siteTitleRef = React.useRef< HTMLInputElement >(); diff --git a/client/landing/gutenboarding/onboarding-block/acquire-intent/site-title.tsx b/client/landing/gutenboarding/onboarding-block/acquire-intent/site-title.tsx index ce88eb2578ab3..1bb662e99e181 100644 --- a/client/landing/gutenboarding/onboarding-block/acquire-intent/site-title.tsx +++ b/client/landing/gutenboarding/onboarding-block/acquire-intent/site-title.tsx @@ -11,6 +11,7 @@ import { ONBOARD_STORE } from '../../stores/onboard'; import AcquireIntentTextInput from './acquire-intent-text-input'; import getTextWidth from './get-text-width'; import tip from './tip'; +import type { OnboardSelect } from '@automattic/data-stores'; interface Props { onSubmit: () => void; @@ -19,7 +20,10 @@ interface Props { const SiteTitle: React.FunctionComponent< Props > = ( { onSubmit, inputRef } ) => { const { __, _x } = useI18n(); - const { siteTitle } = useSelect( ( select ) => select( ONBOARD_STORE ).getState() ); + const { siteTitle } = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getState(), + [] + ); const isAnchorFmSignup = useIsAnchorFm(); const { setSiteTitle } = useDispatch( ONBOARD_STORE ); const [ isTouched, setIsTouched ] = React.useState( false ); diff --git a/client/landing/gutenboarding/onboarding-block/create-site/index.tsx b/client/landing/gutenboarding/onboarding-block/create-site/index.tsx index f6c326da54dd6..c5554764a58fa 100644 --- a/client/landing/gutenboarding/onboarding-block/create-site/index.tsx +++ b/client/landing/gutenboarding/onboarding-block/create-site/index.tsx @@ -6,6 +6,7 @@ import { useInterval } from '../../../../lib/interval/use-interval'; import { useSelectedPlan } from '../../hooks/use-selected-plan'; import { useTrackStep } from '../../hooks/use-track-step'; import { ONBOARD_STORE } from '../../stores/onboard'; +import type { OnboardSelect } from '@automattic/data-stores'; import './style.scss'; @@ -15,7 +16,10 @@ const DURATION_IN_MS = 6000; /* eslint-disable wpcalypso/jsx-classname-namespace */ const CreateSite: React.FunctionComponent = () => { const { __ } = useI18n(); - const hasPaidDomain = useSelect( ( select ) => select( ONBOARD_STORE ).hasPaidDomain() ); + const hasPaidDomain = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).hasPaidDomain(), + [] + ); const plan = useSelectedPlan(); const steps = React.useRef< string[] >( diff --git a/client/landing/gutenboarding/onboarding-block/designs/index.tsx b/client/landing/gutenboarding/onboarding-block/designs/index.tsx index e808ca943a254..fd5765873a2db 100644 --- a/client/landing/gutenboarding/onboarding-block/designs/index.tsx +++ b/client/landing/gutenboarding/onboarding-block/designs/index.tsx @@ -9,6 +9,7 @@ import useStepNavigation from '../../hooks/use-step-navigation'; import { useTrackStep } from '../../hooks/use-track-step'; import { useIsAnchorFm } from '../../path'; import { ONBOARD_STORE } from '../../stores/onboard'; +import type { OnboardSelect } from '@automattic/data-stores'; import type { Design } from '@automattic/design-picker'; import './style.scss'; @@ -45,14 +46,14 @@ const Designs: React.FunctionComponent = () => { const { setSelectedDesign, setFonts, resetFonts, setRandomizedDesigns } = useDispatch( ONBOARD_STORE ); const { selectedDesign, hasPaidDesign, randomizedDesigns } = useSelect( ( select ) => { - const onboardSelect = select( ONBOARD_STORE ); + const onboardSelect: OnboardSelect = select( ONBOARD_STORE ); return { selectedDesign: onboardSelect.getSelectedDesign(), hasPaidDesign: onboardSelect.hasPaidDesign(), randomizedDesigns: onboardSelect.getRandomizedDesigns(), }; - } ); + }, [] ); const isAnchorFmSignup = useIsAnchorFm(); useTrackStep( 'DesignSelection', () => ( { diff --git a/client/landing/gutenboarding/onboarding-block/domains/index.tsx b/client/landing/gutenboarding/onboarding-block/domains/index.tsx index 6ff3edbd63715..3bf89d6abd1e5 100644 --- a/client/landing/gutenboarding/onboarding-block/domains/index.tsx +++ b/client/landing/gutenboarding/onboarding-block/domains/index.tsx @@ -20,7 +20,7 @@ import { DOMAIN_SUGGESTIONS_STORE } from '../../stores/domain-suggestions'; import { ONBOARD_STORE } from '../../stores/onboard'; import { USER_STORE } from '../../stores/user'; import waitForDomainAvailability from './wait-for-domain-availability'; -import type { DomainSuggestions } from '@automattic/data-stores'; +import type { DomainSuggestions, OnboardSelect, UserSelect } from '@automattic/data-stores'; import './style.scss'; @@ -37,17 +37,30 @@ const DomainsStep: React.FunctionComponent< Props > = ( { isModal } ) => { const { goBack, goNext } = useStepNavigation(); const { goLastLocation } = useLastLocation(); - const domain = useSelect( ( select ) => select( ONBOARD_STORE ).getSelectedDomain() ); + const domain = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedDomain(), + [] + ); // using the selector will get the explicit domain search query with site title as fallback - const domainSearch = useSelect( ( select ) => select( ONBOARD_STORE ).getDomainSearch() ); + const domainSearch = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getDomainSearch(), + [] + ); - const currentUser = useSelect( ( select ) => select( USER_STORE ).getCurrentUser() ); + const currentUser = useSelect( + ( select ) => ( select( USER_STORE ) as UserSelect ).getCurrentUser(), + [] + ); - const isCheckingDomainAvailability = useSelect( ( select ): boolean => - select( 'core/data' ).isResolving( DOMAIN_SUGGESTIONS_STORE, 'isAvailable', [ - domain?.domain_name, - ] ) + const isCheckingDomainAvailability = useSelect( + ( select ): boolean => + ( + select( 'core/data' ) as { + isResolving: ( store: string, resolver: string, args: Array< unknown > ) => boolean; + } + ).isResolving( DOMAIN_SUGGESTIONS_STORE, 'isAvailable', [ domain?.domain_name ] ), + [ domain?.domain_name ] ); const { setDomain, setDomainSearch, setHasUsedDomainsStep } = useDispatch( ONBOARD_STORE ); diff --git a/client/landing/gutenboarding/onboarding-block/edit.tsx b/client/landing/gutenboarding/onboarding-block/edit.tsx index 69f2d2c212f1b..e470d4abafaba 100644 --- a/client/landing/gutenboarding/onboarding-block/edit.tsx +++ b/client/landing/gutenboarding/onboarding-block/edit.tsx @@ -27,6 +27,7 @@ import Language from './language'; import Plans from './plans'; import StylePreview from './style-preview'; import type { Attributes } from './types'; +import type { OnboardSelect, SiteSelect } from '@automattic/data-stores'; import type { BlockEditProps } from '@wordpress/blocks'; import './colors.scss'; @@ -38,7 +39,7 @@ const OnboardingEdit: React.FunctionComponent< BlockEditProps< Attributes > > = const { hasSiteTitle, hasSelectedDesign, hasSelectedDesignWithoutFonts, isRedirecting } = useSelect( ( select ) => { - const onboardSelect = select( ONBOARD_STORE ); + const onboardSelect: OnboardSelect = select( ONBOARD_STORE ); return { hasSiteTitle: onboardSelect.hasSiteTitle(), @@ -51,7 +52,7 @@ const OnboardingEdit: React.FunctionComponent< BlockEditProps< Attributes > > = ); const { isCreatingSite, newSiteError } = useSelect( ( select ) => { - const { isFetchingSite, getNewSiteError } = select( SITE_STORE ); + const { isFetchingSite, getNewSiteError }: SiteSelect = select( SITE_STORE ); return { isCreatingSite: isFetchingSite(), diff --git a/client/landing/gutenboarding/onboarding-block/features/index.tsx b/client/landing/gutenboarding/onboarding-block/features/index.tsx index d6764e9916109..157018fb985ba 100644 --- a/client/landing/gutenboarding/onboarding-block/features/index.tsx +++ b/client/landing/gutenboarding/onboarding-block/features/index.tsx @@ -16,7 +16,7 @@ import useStepNavigation from '../../hooks/use-step-navigation'; import { useTrackStep } from '../../hooks/use-track-step'; import { ONBOARD_STORE } from '../../stores/onboard'; import { WPCOM_FEATURES_STORE } from '../../stores/wpcom-features'; -import type { WPCOMFeatures } from '@automattic/data-stores'; +import type { OnboardSelect, WPCOMFeatures, WpcomFeaturesSelect } from '@automattic/data-stores'; import './style.scss'; @@ -28,9 +28,15 @@ const FeaturesStep: React.FunctionComponent = () => { const { __ } = useI18n(); const { goBack, goNext } = useStepNavigation(); - const allFeatures = useSelect( ( select ) => select( WPCOM_FEATURES_STORE ).getAllFeatures() ); + const allFeatures = useSelect( + ( select ) => ( select( WPCOM_FEATURES_STORE ) as WpcomFeaturesSelect ).getAllFeatures(), + [] + ); - const selectedFeatures = useSelect( ( select ) => select( ONBOARD_STORE ).getSelectedFeatures() ); + const selectedFeatures = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedFeatures(), + [] + ); const { addFeature, removeFeature } = useDispatch( ONBOARD_STORE ); const hasSelectedFeatures = selectedFeatures.length > 0; diff --git a/client/landing/gutenboarding/onboarding-block/language/index.tsx b/client/landing/gutenboarding/onboarding-block/language/index.tsx index 61424a0b693d4..8c74bd641fdf9 100644 --- a/client/landing/gutenboarding/onboarding-block/language/index.tsx +++ b/client/landing/gutenboarding/onboarding-block/language/index.tsx @@ -11,6 +11,7 @@ import { Step, usePath } from '../../path'; import { I18N_STORE } from '../../stores/i18n'; import { USER_STORE } from '../../stores/user'; import type { StepNameType } from '../../path'; +import type { I18nSelect, UserSelect } from '@automattic/data-stores'; import './style.scss'; @@ -23,12 +24,17 @@ interface Props { const LanguageStep: React.FunctionComponent< Props > = ( { previousStep } ) => { const { __ } = useI18n(); - const currentUser = useSelect( ( select ) => select( USER_STORE ).getCurrentUser() ); + const currentUser = useSelect( + ( select ) => ( select( USER_STORE ) as UserSelect ).getCurrentUser(), + [] + ); - const localizedLanguageNames = useSelect( ( select ) => - select( I18N_STORE ).getLocalizedLanguageNames( - currentUser?.language ?? LOCALIZED_LANGUAGE_NAMES_FALLBACK_LOCALE - ) + const localizedLanguageNames = useSelect( + ( select ) => + ( select( I18N_STORE ) as I18nSelect ).getLocalizedLanguageNames( + currentUser?.language ?? LOCALIZED_LANGUAGE_NAMES_FALLBACK_LOCALE + ), + [ currentUser?.language ] ); // keep a static reference to the previous step diff --git a/client/landing/gutenboarding/onboarding-block/plans/index.tsx b/client/landing/gutenboarding/onboarding-block/plans/index.tsx index f917a5efd7861..17e1b17004426 100644 --- a/client/landing/gutenboarding/onboarding-block/plans/index.tsx +++ b/client/landing/gutenboarding/onboarding-block/plans/index.tsx @@ -13,7 +13,7 @@ import { useTrackStep } from '../../hooks/use-track-step'; import { Step, usePath } from '../../path'; import { ONBOARD_STORE } from '../../stores/onboard'; import { PLANS_STORE } from '../../stores/plans'; -import type { Plans } from '@automattic/data-stores'; +import type { Plans, PlansSelect, OnboardSelect } from '@automattic/data-stores'; interface Props { isModal?: boolean; @@ -30,21 +30,24 @@ const PlansStep: React.FunctionComponent< Props > = ( { isModal } ) => { const [ billingPeriod, setBillingPeriod ] = React.useState< Plans.PlanBillingPeriod >(); const { domain, selectedFeatures, selectedPlanProductId } = useSelect( ( select ) => { - const onboardStore = select( ONBOARD_STORE ); + const onboardStore: OnboardSelect = select( ONBOARD_STORE ); return { domain: onboardStore.getSelectedDomain(), selectedFeatures: onboardStore.getSelectedFeatures(), selectedPlanProductId: onboardStore.getPlanProductId(), }; - } ); - - const { isPlanProductFree, selectedPlanProduct } = useSelect( ( select ) => { - const plansStore = select( PLANS_STORE ); - return { - isPlanProductFree: plansStore.isPlanProductFree, - selectedPlanProduct: plansStore.getPlanProductById( selectedPlanProductId ), - }; - } ); + }, [] ); + + const { isPlanProductFree, selectedPlanProduct } = useSelect( + ( select ) => { + const plansStore: PlansSelect = select( PLANS_STORE ); + return { + isPlanProductFree: plansStore.isPlanProductFree, + selectedPlanProduct: plansStore.getPlanProductById( selectedPlanProductId ), + }; + }, + [ selectedPlanProductId ] + ); const { setDomain, updatePlan, setHasUsedPlansStep } = useDispatch( ONBOARD_STORE ); React.useEffect( () => { diff --git a/client/landing/gutenboarding/onboarding-block/style-preview/font-select.tsx b/client/landing/gutenboarding/onboarding-block/style-preview/font-select.tsx index 4a0f266c3fd34..bdcc005a2c637 100644 --- a/client/landing/gutenboarding/onboarding-block/style-preview/font-select.tsx +++ b/client/landing/gutenboarding/onboarding-block/style-preview/font-select.tsx @@ -8,13 +8,18 @@ import classnames from 'classnames'; import * as React from 'react'; import { useFontPairings } from '../../fonts'; import { ONBOARD_STORE } from '../../stores/onboard'; +import type { OnboardSelect } from '@automattic/data-stores'; const FontSelect: React.FunctionComponent = () => { const { __ } = useI18n(); - const { selectedDesign, selectedFonts } = useSelect( ( select ) => - select( ONBOARD_STORE ).getState() + const { selectedDesign, selectedFonts } = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getState(), + [] + ); + const { getRandomizedDesigns } = useSelect( + ( select ) => select( ONBOARD_STORE ) as OnboardSelect, + [] ); - const { getRandomizedDesigns } = useSelect( ( select ) => select( ONBOARD_STORE ) ); const { setFonts } = useDispatch( ONBOARD_STORE ); const [ isOpen, setIsOpen ] = React.useState( false ); diff --git a/client/landing/gutenboarding/onboarding-block/style-preview/index.tsx b/client/landing/gutenboarding/onboarding-block/style-preview/index.tsx index f54411c9dd542..49c2042f636f5 100644 --- a/client/landing/gutenboarding/onboarding-block/style-preview/index.tsx +++ b/client/landing/gutenboarding/onboarding-block/style-preview/index.tsx @@ -10,11 +10,15 @@ import FontSelect from './font-select'; import Preview from './preview'; import ViewportSelect from './viewport-select'; import type { Viewport } from './types'; +import type { OnboardSelect } from '@automattic/data-stores'; import './style.scss'; const StylePreview: React.FunctionComponent = () => { - const { getSelectedFonts } = useSelect( ( select ) => select( ONBOARD_STORE ) ); + const { getSelectedFonts } = useSelect( + ( select ) => select( ONBOARD_STORE ) as OnboardSelect, + [] + ); const { __ } = useI18n(); const { goBack, goNext } = useStepNavigation(); diff --git a/client/landing/gutenboarding/onboarding-block/style-preview/preview.tsx b/client/landing/gutenboarding/onboarding-block/style-preview/preview.tsx index f1fd1ec78c530..153da4b305ff8 100644 --- a/client/landing/gutenboarding/onboarding-block/style-preview/preview.tsx +++ b/client/landing/gutenboarding/onboarding-block/style-preview/preview.tsx @@ -6,6 +6,7 @@ import { useAnchorFmParams } from '../../../gutenboarding/path'; import { useFontPairings } from '../../fonts'; import { ONBOARD_STORE } from '../../stores/onboard'; import type { Viewport } from './types'; +import type { OnboardSelect } from '@automattic/data-stores'; import type { FontPair } from '@automattic/design-picker'; function getFontsLoadingHTML( effectiveFontPairings: readonly FontPair[] ) { @@ -52,8 +53,9 @@ interface Props { const Preview: React.FunctionComponent< Props > = ( { viewport } ) => { const language = useLocale(); const [ previewHtml, setPreviewHtml ] = React.useState< string >(); - const { selectedDesign, selectedFonts, siteTitle } = useSelect( ( select ) => - select( ONBOARD_STORE ).getState() + const { selectedDesign, selectedFonts, siteTitle } = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getState(), + [] ); const { anchorFmPodcastId } = useAnchorFmParams(); diff --git a/client/landing/gutenboarding/types.d.ts b/client/landing/gutenboarding/types.d.ts index 9ece1482cba87..a151b715df2aa 100644 --- a/client/landing/gutenboarding/types.d.ts +++ b/client/landing/gutenboarding/types.d.ts @@ -1,3 +1,376 @@ +declare module '@wordpress/blocks' { + export type AxialDirection = 'horizontal' | 'vertical'; + + export type CSSDirection = 'top' | 'right' | 'bottom' | 'left'; + + export type BlockAlignment = 'left' | 'center' | 'right' | 'wide' | 'full'; + + export interface BlockEditProps< T extends Record< string, any > > extends BlockSaveProps< T > { + readonly clientId: string; + readonly isSelected: boolean; + readonly setAttributes: ( attrs: Partial< T > ) => void; + readonly context: Record< string, unknown >; + } + + export interface BlockIconNormalized { + background?: string | undefined; + foreground?: string | undefined; + shadowColor?: string | undefined; + src: Dashicon.Icon | ReactElement | ComponentType; + } + + export type BlockIcon = BlockIconNormalized[ 'src' ] | BlockIconNormalized; + + export interface BlockSaveProps< T extends Record< string, any > > { + readonly className: string; + readonly attributes: Readonly< T >; + } + + export interface BlockStyle { + readonly name: string; + readonly label: string; + readonly isDefault?: boolean | undefined; + } + + export interface ColorProps { + background: boolean; + gradients: boolean; + link: boolean; + text: boolean; + } + + export interface TypographyProps { + fontSize: boolean; + lineHeight: boolean; + } + + export interface SpacingProps { + blockGap: boolean | AxialDirection[]; + margin: boolean | CSSDirection[]; + padding: boolean | CSSDirection[]; + } + + type BlockExampleInnerBlock = Partial< Block > & + Pick< Block, 'name' | 'attributes' > & { + innerBlocks?: ReadonlyArray< BlockExampleInnerBlock >; + }; + + export interface Block< T extends Record< string, any > > { + readonly apiVersion?: number; + readonly attributes: { + readonly [ k in keyof T ]: BlockAttribute< T[ k ] extends Array< infer U > ? U : T[ k ] >; + }; + readonly category: string; + readonly deprecated?: ReadonlyArray< BlockDeprecation< T > > | undefined; + readonly description?: string | undefined; + readonly edit?: ComponentType< BlockEditProps< T > > | undefined; + readonly editorScript?: string; + readonly editorStyle?: string; + readonly example?: Readonly< + Partial< Block > & { innerBlocks?: ReadonlyArray< BlockExampleInnerBlock > } + >; + readonly icon: BlockIconNormalized; + readonly keywords?: readonly string[] | undefined; + readonly parent?: readonly string[] | undefined; + readonly ancestor?: readonly string[] | undefined; + readonly providesContext?: Record< string, keyof T >; + readonly name: string; + readonly save: ComponentType< BlockSaveProps< T > >; + readonly script?: string; + readonly style?: string; + readonly styles?: readonly BlockStyle[] | undefined; + readonly supports?: BlockSupports | undefined; + readonly textdomain?: string; + readonly title: string; + readonly transforms?: + | { + readonly from?: ReadonlyArray< Transform< T > > | undefined; + readonly to?: readonly Transform[] | undefined; + } + | undefined; + readonly usesContext?: string[]; + readonly version?: string; + getEditWrapperProps?( attrs: T ): Record< string, string | number | boolean >; + merge?( attributes: T, attributesToMerge: T ): Partial< T >; + } + + export type BlockConfiguration< T extends Record< string, any > > = Partial< + Omit< Block< T >, 'icon' > + > & + Pick< Block< T >, 'attributes' | 'category' | 'title' > & { + icon?: BlockIcon | undefined; + }; + + export interface BlockInstance< T extends Record< string, any > = { [ k: string ]: any } > { + readonly attributes: T; + readonly clientId: string; + readonly innerBlocks: BlockInstance[]; + readonly isValid: boolean; + readonly name: string; + readonly originalContent?: string | undefined; + } + + export interface BlockDeprecation< + N extends Record< string, any >, + O extends Record< string, any > = Record< string, any > + > extends Pick< Block< O >, 'attributes' | 'save' | 'supports' > { + isEligible?( attributes: Record< string, any >, innerBlocks: BlockInstance[] ): boolean; + migrate?( attributes: O, innerBlocks: BlockInstance[] ): N | [ N, BlockInstance[] ]; + } + + export interface BlockSupports { + readonly align?: boolean | readonly BlockAlignment[] | undefined; + readonly alignWide?: boolean | undefined; + readonly anchor?: boolean | undefined; + readonly color?: Partial< ColorProps > | undefined; + readonly customClassName?: boolean | undefined; + readonly className?: boolean | undefined; + readonly html?: boolean | undefined; + readonly inserter?: boolean | undefined; + readonly multiple?: boolean | undefined; + readonly reusable?: boolean | undefined; + readonly spacing?: Partial< SpacingProps > | undefined; + readonly lock?: boolean | undefined; + readonly typography?: Partial< TypographyProps > | undefined; + } + + export namespace AttributeSource { + type Attribute = { + source: 'attribute'; + attribute: string; + selector?: string | undefined; + } & ( + | { + type: 'boolean'; + default?: boolean | undefined; + } + | { + type: 'number'; + default?: number | undefined; + } + | { + type: 'string'; + default?: string | undefined; + } + ); + + interface Children { + source: 'children'; + type: 'array'; + selector?: string | undefined; + } + + interface HTML { + source: 'html'; + type: 'string'; + multiline?: 'li' | 'p' | undefined; + selector?: string | undefined; + default?: string | undefined; + } + + interface Meta { + source: 'meta'; + type: 'string'; + meta: string; + default?: string | undefined; + } + + interface Query< T > { + source: 'query'; + type: 'array'; + selector: string; + query: { + [ k in keyof T ]: BlockAttribute< T[ k ] extends Array< infer U > ? U : T[ k ] >; + }; + default?: any[] | undefined; + } + + interface Text { + source: 'text'; + type: 'string'; + selector?: string | undefined; + default?: string | undefined; + } + + type None = + | ( { + source?: never | undefined; + } & ( + | { + type: 'array'; + default?: any[] | undefined; + } + | { + type: 'object'; + default?: object | undefined; + } + | { + type: 'boolean'; + default?: boolean | undefined; + } + | { + type: 'number'; + default?: number | undefined; + } + | { + type: 'string'; + default?: string | undefined; + } + ) ) + | 'array' + | 'object' + | 'boolean' + | 'number' + | 'string'; + } + + export type BlockAttribute< T > = + | AttributeSource.Attribute + | AttributeSource.Children + | AttributeSource.HTML + | AttributeSource.Meta + | AttributeSource.Query< T > + | AttributeSource.Text + | AttributeSource.None; + + export type TransformRawSchema = { + [ k in keyof HTMLElementTagNameMap | '#text' ]?: { + attributes?: string[] | undefined; + require?: Array< keyof HTMLElementTagNameMap > | undefined; + classes?: Array< string | RegExp > | undefined; + children?: TransformRawSchema | undefined; + }; + }; + + export interface TransformBlock< T extends Record< string, any > > { + type: 'block'; + priority?: number | undefined; + blocks: string[]; + isMatch?( attributes: T, block: string | string[] ): boolean; + isMultiBlock?: boolean | undefined; + transform( attributes: T ): BlockInstance< Partial< T > >; + } + + export interface TransformEnter< T extends Record< string, any > > { + type: 'enter'; + priority?: number | undefined; + regExp: RegExp; + transform(): BlockInstance< Partial< T > >; + } + + export interface TransformFiles< T extends Record< string, any > > { + type: 'files'; + priority?: number | undefined; + isMatch?( files: FileList ): boolean; + transform( + files: FileList, + onChange?: ( id: string, attrs: T ) => void + ): BlockInstance< Partial< T > >; + } + + export interface TransformPrefix< T extends Record< string, any > > { + type: 'prefix'; + priority?: number | undefined; + prefix: string; + transform( content: string ): BlockInstance< Partial< T > >; + } + + export interface TransformRaw< T extends Record< string, any > > { + type: 'raw'; + priority?: number | undefined; + selector?: string | undefined; + schema?: TransformRawSchema | undefined; + isMatch?( node: Node ): boolean; + transform?( node: Node ): BlockInstance< Partial< T > > | void; + } + + export interface TransformShortcode< T extends Record< string, any > > { + type: 'shortcode'; + priority?: number | undefined; + tag: string; + transform?( attributes: any, match: ShortcodeMatch ): BlockInstance< T >; + attributes?: any; + } + + export type Transform< T extends Record< string, any > = Record< string, any > > = + | TransformBlock< T > + | TransformEnter< T > + | TransformFiles< T > + | TransformPrefix< T > + | TransformRaw< T > + | TransformShortcode< T >; + + export type BlockAttributes = Record< string, any >; + + export type InnerBlockTemplate = [ string, BlockAttributes?, InnerBlockTemplate[]? ]; + + export type BlockVariationScope = 'block' | 'inserter' | 'transform'; + + export interface BlockVariation< Attributes extends BlockAttributes = BlockAttributes > { + name: string; + title: string; + description?: string; + category?: string; + icon?: BlockIcon; + isDefault?: boolean; + attributes?: Attributes; + innerBlocks?: BlockInstance | InnerBlockTemplate[]; + example?: + | BlockExampleInnerBlock + | { + attributes: Attributes; + innerBlocks?: InnerBlockTemplate[]; + }; + scope?: BlockVariationScope[]; + keywords?: string[]; + isActive?: + | ( ( blockAttributes: Attributes, variationAttributes: Attributes ) => boolean ) + | string[]; + } + + export function createBlock< T extends Record< string, any > >( + name: string, + attributes?: Partial< T >, + innerBlocks?: BlockInstance[] + ): BlockInstance< T >; + + export function registerBlockType< TAttributes extends Record< string, any > >( + metadata: BlockConfiguration< TAttributes >, + settings?: Partial< BlockConfiguration< TAttributes > > + ): Block< TAttributes > | undefined; + export function registerBlockType< TAttributes extends Record< string, any > >( + name: string, + settings: BlockConfiguration< TAttributes > + ): Block< TAttributes > | undefined; +} + +declare module '@wordpress/block-editor' { + import { BlockInstance } from '@wordpress/blocks'; + import { ComponentType, ReactNode } from 'react'; + import { EditorSettings, EditorBlockListSettings } from '../'; + + declare namespace BlockEditorProvider { + interface Props { + children: ReactNode; + onChange?( blocks: BlockInstance[] ): void; + onInput?( blocks: BlockInstance[] ): void; + settings?: Partial< EditorSettings & EditorBlockListSettings > | undefined; + useSubRegistry?: boolean | undefined; + value?: BlockInstance[] | undefined; + } + } + declare const BlockEditorProvider: ComponentType< BlockEditorProvider.Props >; + + declare namespace BlockList { + interface Props { + className?: string | undefined; + renderAppender?(): JSX.Element; + rootClientId?: string | undefined; + } + } + declare const BlockList: ComponentType< BlockList.Props >; +} + declare module '@wordpress/keyboard-shortcuts' { type ShortcutProts = { children: JSX.Element }; export function ShortcutProvider( props: ShortcutProts ): JSX.Element; diff --git a/client/landing/stepper/declarative-flow/anchor-fm-flow.ts b/client/landing/stepper/declarative-flow/anchor-fm-flow.ts index 258110cf8d4e6..b4bfbf2e53db3 100644 --- a/client/landing/stepper/declarative-flow/anchor-fm-flow.ts +++ b/client/landing/stepper/declarative-flow/anchor-fm-flow.ts @@ -9,6 +9,7 @@ import LoginStep from './internals/steps-repository/login'; import PodcastTitleStep from './internals/steps-repository/podcast-title'; import ProcessingStep from './internals/steps-repository/processing-step'; import type { Flow, ProvidedDependencies } from './internals/types'; +import type { SiteSelect } from '@automattic/data-stores'; export function isAnchorFmFlow() { const sanitizePodcast = ( id: string ) => id.replace( /[^a-zA-Z0-9]/g, '' ); @@ -32,7 +33,7 @@ const anchorFmFlow: Flow = { useStepNavigation( currentStep, navigate ) { const flowName = this.name; - const { getNewSite } = useSelect( ( select ) => select( SITE_STORE ) ); + const { getNewSite } = useSelect( ( select ) => select( SITE_STORE ) as SiteSelect, [] ); const siteSlugParam = useSiteSlugParam(); function submit( providedDependencies: ProvidedDependencies = {} ) { diff --git a/client/landing/stepper/declarative-flow/copy-site.tsx b/client/landing/stepper/declarative-flow/copy-site.tsx index 260459abbb89b..e48110bfd9f0c 100644 --- a/client/landing/stepper/declarative-flow/copy-site.tsx +++ b/client/landing/stepper/declarative-flow/copy-site.tsx @@ -23,6 +23,7 @@ import { Flow, ProvidedDependencies, } from './internals/types'; +import type { SiteSelect } from '@automattic/data-stores'; function useIsValidSite() { const urlQueryParams = useQuery(); @@ -35,16 +36,19 @@ function useIsValidSite() { isFetchingSiteDetails, isFetchingError, site: sourceSite, - } = useSelect( ( select ) => { - if ( ! sourceSlug ) { - return {}; - } - return { - isFetchingError: select( SITE_STORE ).getFetchingSiteError(), - isFetchingSiteDetails: select( SITE_STORE ).isFetchingSiteDetails(), - site: select( SITE_STORE ).getSite( sourceSlug ), - }; - } ); + } = useSelect( + ( select ) => { + if ( ! sourceSlug ) { + return {}; + } + return { + isFetchingError: ( select( SITE_STORE ) as SiteSelect ).getFetchingSiteError(), + isFetchingSiteDetails: ( select( SITE_STORE ) as SiteSelect ).isFetchingSiteDetails(), + site: ( select( SITE_STORE ) as SiteSelect ).getSite( sourceSlug ), + }; + }, + [ sourceSlug ] + ); useEffect( () => { if ( isFetchingSiteDetails && siteRequestStatus === 'init' ) { diff --git a/client/landing/stepper/declarative-flow/free.ts b/client/landing/stepper/declarative-flow/free.ts index e73393e2a2c49..adf0964179c2a 100644 --- a/client/landing/stepper/declarative-flow/free.ts +++ b/client/landing/stepper/declarative-flow/free.ts @@ -24,6 +24,7 @@ import { Flow, ProvidedDependencies, } from './internals/types'; +import type { OnboardSelect, UserSelect } from '@automattic/data-stores'; const free: Flow = { name: FREE_FLOW, @@ -52,7 +53,10 @@ const free: Flow = { const flowProgress = useFlowProgress( { stepName: _currentStep, flowName } ); setStepProgress( flowProgress ); const siteSlug = useSiteSlug(); - const selectedDesign = useSelect( ( select ) => select( ONBOARD_STORE ).getSelectedDesign() ); + const selectedDesign = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedDesign(), + [] + ); // trigger guides on step movement, we don't care about failures or response wpcom.req.post( @@ -139,7 +143,10 @@ const free: Flow = { }, useAssertConditions(): AssertConditionResult { - const userIsLoggedIn = useSelect( ( select ) => select( USER_STORE ).isCurrentUserLoggedIn() ); + const userIsLoggedIn = useSelect( + ( select ) => ( select( USER_STORE ) as UserSelect ).isCurrentUserLoggedIn(), + [] + ); let result: AssertConditionResult = { state: AssertConditionState.SUCCESS }; const queryParams = new URLSearchParams( window.location.search ); diff --git a/client/landing/stepper/declarative-flow/import-flow.ts b/client/landing/stepper/declarative-flow/import-flow.ts index f2845267e7edd..be8ec7e89a527 100644 --- a/client/landing/stepper/declarative-flow/import-flow.ts +++ b/client/landing/stepper/declarative-flow/import-flow.ts @@ -23,6 +23,7 @@ import PatternAssembler from './internals/steps-repository/pattern-assembler'; import ProcessingStep from './internals/steps-repository/processing-step'; import SiteCreationStep from './internals/steps-repository/site-creation-step'; import { Flow, ProvidedDependencies } from './internals/types'; +import type { OnboardSelect } from '@automattic/data-stores'; const importFlow: Flow = { name: IMPORT_FOCUSED_FLOW, @@ -53,7 +54,10 @@ const importFlow: Flow = { const urlQueryParams = useQuery(); const siteSlugParam = useSiteSlugParam(); const { setPendingAction } = useDispatch( ONBOARD_STORE ); - const selectedDesign = useSelect( ( select ) => select( ONBOARD_STORE ).getSelectedDesign() ); + const selectedDesign = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedDesign(), + [] + ); const flowProgress = useSiteSetupFlowProgress( _currentStep, 'import' ); if ( flowProgress ) { diff --git a/client/landing/stepper/declarative-flow/internals/index.tsx b/client/landing/stepper/declarative-flow/internals/index.tsx index b8c7b8253e9e6..3b54b089854e1 100644 --- a/client/landing/stepper/declarative-flow/internals/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/index.tsx @@ -22,6 +22,7 @@ import StepperLoader from './components/stepper-loader'; import VideoPressIntroBackground from './steps-repository/intro/videopress-intro-background'; import { AssertConditionState, Flow, StepperStep } from './types'; import './global.scss'; +import type { OnboardSelect, StepperInternalSelect } from '@automattic/data-stores'; const kebabCase = ( value: string ) => value.replace( /([a-z0-9])([A-Z])/g, '$1-$2' ).toLowerCase(); @@ -46,10 +47,16 @@ export const FlowRenderer: React.FC< { flow: Flow } > = ( { flow } ) => { const history = useHistory(); const { search } = useLocation(); const { setStepData } = useDispatch( STEPPER_INTERNAL_STORE ); - const intent = useSelect( ( select ) => select( ONBOARD_STORE ).getIntent() ); + const intent = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getIntent(), + [] + ); const ref = useQuery().get( 'ref' ) || ''; - const stepProgress = useSelect( ( select ) => select( ONBOARD_STORE ).getStepProgress() ); + const stepProgress = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getStepProgress(), + [] + ); const progressValue = stepProgress ? stepProgress.progress / stepProgress.count : 0; const [ previousProgress, setPreviousProgress ] = useState( stepProgress ? stepProgress.progress : 0 @@ -88,7 +95,10 @@ export const FlowRenderer: React.FC< { flow: Flow } > = ( { flow } ) => { const stepNavigation = flow.useStepNavigation( currentStepRoute, navigate ); // Retrieve any extra step data from the stepper-internal store. This will be passed as a prop to the current step. - const stepData = useSelect( ( select ) => select( STEPPER_INTERNAL_STORE ).getStepData() ); + const stepData = useSelect( + ( select ) => ( select( STEPPER_INTERNAL_STORE ) as StepperInternalSelect ).getStepData(), + [] + ); flow.useSideEffect?.( currentStepRoute, navigate ); diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/assign-trial-plan/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/assign-trial-plan/index.tsx index 8e9a490b38ff0..e4e668cc2005d 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/assign-trial-plan/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/assign-trial-plan/index.tsx @@ -9,6 +9,7 @@ import { ONBOARD_STORE } from 'calypso/landing/stepper/stores'; import { recordTracksEvent } from 'calypso/lib/analytics/tracks'; import wpcom from 'calypso/lib/wp'; import type { Step } from '../../types'; +import type { OnboardSelect } from '@automattic/data-stores'; import './styles.scss'; @@ -20,8 +21,14 @@ export enum AssignTrialResult { const AssignTrialPlanStep: Step = function AssignTrialPlanStep( { navigation, data, flow } ) { const { submit } = navigation; const { __ } = useI18n(); - const progress = useSelect( ( select ) => select( ONBOARD_STORE ).getProgress() ); - const stepProgress = useSelect( ( select ) => select( ONBOARD_STORE ).getStepProgress() ); + const progress = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getProgress(), + [] + ); + const stepProgress = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getStepProgress(), + [] + ); useEffect( () => { if ( submit ) { diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/automated-copy-site/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/automated-copy-site/index.tsx index 206fb3bbe2e67..f47d8442b2c83 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/automated-copy-site/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/automated-copy-site/index.tsx @@ -5,6 +5,7 @@ import { useSite } from 'calypso/landing/stepper/hooks/use-site'; import { ONBOARD_STORE, SITE_STORE } from 'calypso/landing/stepper/stores'; import wpcom from 'calypso/lib/wp'; import type { Step } from '../../types'; +import type { SiteSelect } from '@automattic/data-stores'; const TIME_CHECK_TRANSFER_STATUS = 3000; @@ -32,14 +33,17 @@ const AutomatedCopySite: Step = function AutomatedCopySite( { navigation } ) { const urlQueryParams = useQuery(); const siteSlug = urlQueryParams.get( 'siteSlug' ); const sourceSlug = urlQueryParams.get( 'sourceSlug' ); - const sourceSite = useSelect( ( select ) => - sourceSlug ? select( SITE_STORE ).getSite( sourceSlug ) : undefined + const sourceSite = useSelect( + ( select ) => + sourceSlug ? ( select( SITE_STORE ) as SiteSelect ).getSite( sourceSlug ) : undefined, + [ sourceSlug ] ); const sourceSiteId = sourceSite?.ID; const { setPendingAction, setProgress } = useDispatch( ONBOARD_STORE ); const { requestLatestAtomicTransfer } = useDispatch( SITE_STORE ); - const { getSiteLatestAtomicTransfer, getSiteLatestAtomicTransferError } = useSelect( ( select ) => - select( SITE_STORE ) + const { getSiteLatestAtomicTransfer, getSiteLatestAtomicTransferError } = useSelect( + ( select ) => select( SITE_STORE ) as SiteSelect, + [] ); useEffect( () => { diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/business-info/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/business-info/index.tsx index 5faa312b9a934..b9fee46f6d7db 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/business-info/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/business-info/index.tsx @@ -11,6 +11,7 @@ import { useQuery } from 'calypso/landing/stepper/hooks/use-query'; import { ONBOARD_STORE, SITE_STORE } from 'calypso/landing/stepper/stores'; import { recordTracksEvent } from 'calypso/lib/analytics/tracks'; import type { Step } from '../../types'; +import type { OnboardSelect, SiteSelect } from '@automattic/data-stores'; import './style.scss'; const ActionSection = styled.div` @@ -36,13 +37,19 @@ const BusinessInfo: Step = function ( props ) { const { goNext, goBack, submit } = props.navigation; const { __ } = useI18n(); - const intent = useSelect( ( select ) => select( ONBOARD_STORE ).getIntent() ); + const intent = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getIntent(), + [] + ); const siteSlug = useQuery().get( 'siteSlug' ); const siteId = useSelect( - ( select ) => siteSlug && select( SITE_STORE ).getSiteIdBySlug( siteSlug ) + ( select ) => siteSlug && ( select( SITE_STORE ) as SiteSelect ).getSiteIdBySlug( siteSlug ), + [ siteSlug ] ); const settings = useSelect( - ( select ) => ( siteId && select( SITE_STORE ).getSiteSettings( siteId ) ) || {} + ( select ) => + ( siteId && ( select( SITE_STORE ) as SiteSelect ).getSiteSettings( siteId ) ) || {}, + [ siteId ] ); const onboardingProfile = settings?.woocommerce_onboarding_profile || {}; const [ profileChanges, setProfileChanges ] = useState< { @@ -51,7 +58,10 @@ const BusinessInfo: Step = function ( props ) { const { saveSiteSettings } = useDispatch( SITE_STORE ); - const stepProgress = useSelect( ( select ) => select( ONBOARD_STORE ).getStepProgress() ); + const stepProgress = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getStepProgress(), + [] + ); function updateProductTypes( type: string ) { const productTypes = getProfileValue( 'product_types' ) || []; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/choose-a-domain/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/choose-a-domain/index.tsx index c387f8cadfd64..0db573febcef2 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/choose-a-domain/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/choose-a-domain/index.tsx @@ -9,6 +9,7 @@ import { ONBOARD_STORE, PRODUCTS_LIST_STORE } from 'calypso/landing/stepper/stor import { recordTracksEvent } from 'calypso/lib/analytics/tracks'; import CalypsoShoppingCartProvider from 'calypso/my-sites/checkout/calypso-shopping-cart-provider'; import type { Step } from '../../types'; +import type { ProductsListSelect, OnboardSelect } from '@automattic/data-stores'; import './style.scss'; @@ -16,13 +17,14 @@ const ChooseADomain: Step = function ChooseADomain( { navigation, flow } ) { const { goNext, goBack, submit } = navigation; const { __ } = useI18n(); const isVideoPressFlow = 'videopress' === flow; - const [ siteTitle, domain, productsList ] = useSelect( ( select ) => { - return [ - select( ONBOARD_STORE ).getSelectedSiteTitle(), - select( ONBOARD_STORE ).getSelectedDomain(), - select( PRODUCTS_LIST_STORE ).getProductsList(), - ]; - } ); + const { siteTitle, domain, productsList } = useSelect( + ( select ) => ( { + siteTitle: ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedSiteTitle(), + domain: ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedDomain(), + productsList: ( select( PRODUCTS_LIST_STORE ) as ProductsListSelect ).getProductsList(), + } ), + [] + ); const { setDomain } = useDispatch( ONBOARD_STORE ); const onSkip = () => { diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/choose-a-plan/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/choose-a-plan/index.tsx index 94104e54f373a..3fd6c6d99bba0 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/choose-a-plan/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/choose-a-plan/index.tsx @@ -5,7 +5,6 @@ import { useSelect, useDispatch } from '@wordpress/data'; import { sprintf } from '@wordpress/i18n'; import { useI18n } from '@wordpress/react-i18n'; import React from 'react'; -import { Plans } from 'calypso/../packages/data-stores/src'; import { StepContainer } from 'calypso/../packages/onboarding/src'; import { PlansIntervalToggle } from 'calypso/../packages/plans-grid/src'; import { useSupportedPlans } from 'calypso/../packages/plans-grid/src/hooks'; @@ -18,7 +17,14 @@ import { recordTracksEvent } from 'calypso/lib/analytics/tracks'; import { domainRegistration } from 'calypso/lib/cart-values/cart-items'; import { cartManagerClient } from 'calypso/my-sites/checkout/cart-manager-client'; import type { Step } from '../../types'; -import type { PlanSimplifiedFeature } from 'calypso/../packages/data-stores/src/plans'; +import type { + Plans, + PlansSelect, + PlanSimplifiedFeature, + OnboardSelect, + SiteSelect, + UserSelect, +} from '@automattic/data-stores'; import 'calypso/../packages/plans-grid/src/plans-grid/style.scss'; import 'calypso/../packages/plans-grid/src/plans-table/style.scss'; @@ -41,13 +47,23 @@ const ChooseAPlan: Step = function ChooseAPlan( { navigation, flow } ) { const visibility = useNewSiteVisibility(); const { supportedPlans, maxAnnualDiscount } = useSupportedPlans( locale, billingPeriod ); - const currentUser = useSelect( ( select ) => select( USER_STORE ).getCurrentUser() ); - const domain = useSelect( ( select ) => select( ONBOARD_STORE ).getSelectedDomain() ); - const siteDescription = useSelect( ( select ) => - select( ONBOARD_STORE ).getSelectedSiteDescription() + const currentUser = useSelect( + ( select ) => ( select( USER_STORE ) as UserSelect ).getCurrentUser(), + [] ); - const getPlanProduct = useSelect( ( select ) => select( PLANS_STORE ).getPlanProduct ); - const { getNewSite } = useSelect( ( select ) => select( SITE_STORE ) ); + const domain = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedDomain(), + [] + ); + const siteDescription = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedSiteDescription(), + [] + ); + const getPlanProduct = useSelect( + ( select ) => ( select( PLANS_STORE ) as PlansSelect ).getPlanProduct, + [] + ); + const { getNewSite } = useSelect( ( select ) => select( SITE_STORE ) as SiteSelect, [] ); const { createVideoPressSite, setSelectedSite, setPendingAction, setProgress } = useDispatch( ONBOARD_STORE ); diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/components/setup-form/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/components/setup-form/index.tsx index 163c5adeda53e..bf0b3ee225e4d 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/components/setup-form/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/components/setup-form/index.tsx @@ -3,12 +3,12 @@ import { Button, FormInputValidation } from '@automattic/components'; import { TextControl } from '@wordpress/components'; import { useI18n } from '@wordpress/react-i18n'; import { Dispatch, FormEvent, ReactChild, SetStateAction, useEffect } from 'react'; -import { SiteDetails } from 'calypso/../packages/data-stores/src'; import { ForwardedAutoresizingFormTextarea } from 'calypso/blocks/comments/autoresizing-form-textarea'; import FormFieldset from 'calypso/components/forms/form-fieldset'; import FormLabel from 'calypso/components/forms/form-label'; import { SiteIconWithPicker } from 'calypso/components/site-icon-with-picker'; import { useSiteSlugParam } from 'calypso/landing/stepper/hooks/use-site-slug-param'; +import type { SiteDetails } from '@automattic/data-stores'; import './style.scss'; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/courses/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/courses/index.tsx index 91cbb50ec67fb..63eed4da5f3ed 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/courses/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/courses/index.tsx @@ -9,6 +9,7 @@ import { ONBOARD_STORE } from 'calypso/landing/stepper/stores'; import { recordTracksEvent } from 'calypso/lib/analytics/tracks'; import CoursesFooter from './footer'; import type { Step } from '../../types'; +import type { OnboardSelect } from '@automattic/data-stores'; import './style.scss'; /** @@ -21,7 +22,7 @@ const CoursesStep: Step = function CoursesStep( { navigation } ) { const courseSlug = COURSE_SLUGS.BLOGGING_QUICK_START; const { isCourseComplete } = useCourseData( courseSlug ); const hideSkip = isMobile && isCourseComplete; - const { getIntent } = useSelect( ( select ) => select( ONBOARD_STORE ) ); + const { getIntent } = useSelect( ( select ) => select( ONBOARD_STORE ) as OnboardSelect, [] ); return ( <> diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/design-setup/anchor-fm-design-picker.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/design-setup/anchor-fm-design-picker.tsx index 7b80941176d91..890f1994e54c5 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/design-setup/anchor-fm-design-picker.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/design-setup/anchor-fm-design-picker.tsx @@ -14,6 +14,7 @@ import { ANCHOR_FM_THEMES } from './anchor-fm-themes'; import { STEP_NAME } from './constants'; import type { Step } from '../../types'; import './style.scss'; +import type { OnboardSelect, SiteSelect, UserSelect } from '@automattic/data-stores'; import type { Design } from '@automattic/design-picker'; const AnchorFmDesignPicker: Step = ( { navigation, flow } ) => { @@ -23,16 +24,26 @@ const AnchorFmDesignPicker: Step = ( { navigation, flow } ) => { const reduxDispatch = useReduxDispatch(); const { setPendingAction, createSite } = useDispatch( ONBOARD_STORE ); const { setDesignOnSite } = useDispatch( SITE_STORE ); - const selectedDesign = useSelect( ( select ) => select( ONBOARD_STORE ).getSelectedDesign() ); - const { anchorPodcastId, anchorEpisodeId, anchorSpotifyUrl } = useSelect( ( select ) => - select( ONBOARD_STORE ).getState() + const selectedDesign = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedDesign(), + [] + ); + const { anchorPodcastId, anchorEpisodeId, anchorSpotifyUrl } = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getState(), + [] ); const visibility = useNewSiteVisibility(); - const currentUser = useSelect( ( select ) => select( USER_STORE ).getCurrentUser() ); - const newUser = useSelect( ( select ) => select( USER_STORE ).getNewUser() ); - const { getNewSite } = useSelect( ( select ) => select( SITE_STORE ) ); + const currentUser = useSelect( + ( select ) => ( select( USER_STORE ) as UserSelect ).getCurrentUser(), + [] + ); + const newUser = useSelect( + ( select ) => ( select( USER_STORE ) as UserSelect ).getNewUser(), + [] + ); + const { getNewSite } = useSelect( ( select ) => select( SITE_STORE ) as SiteSelect, [] ); const pickDesign = ( _selectedDesign: Design | undefined = selectedDesign ) => { if ( ! _selectedDesign ) { diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/design-setup/design-picker-design-title.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/design-setup/design-picker-design-title.tsx index 6b100f688fe44..bf392c4a0d7e9 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/design-setup/design-picker-design-title.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/design-setup/design-picker-design-title.tsx @@ -3,6 +3,7 @@ import { PremiumBadge, WooCommerceBundledBadge } from '@automattic/design-picker import { useSelect } from '@wordpress/data'; import { useSite } from '../../../../hooks/use-site'; import { SITE_STORE } from '../../../../stores'; +import type { SiteSelect } from '@automattic/data-stores'; import type { Design } from '@automattic/design-picker'; import type { FC } from 'react'; @@ -19,7 +20,12 @@ const DesignPickerDesignTitle: FC< Props > = ( { designTitle, selectedDesign } ) const isPremiumThemeAvailable = Boolean( useSelect( ( select ) => - site && select( SITE_STORE ).siteHasFeature( site.ID, WPCOM_FEATURES_PREMIUM_THEMES ) + site && + ( select( SITE_STORE ) as SiteSelect ).siteHasFeature( + site.ID, + WPCOM_FEATURES_PREMIUM_THEMES + ), + [ site ] ) ); diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/design-setup/unified-design-picker.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/design-setup/unified-design-picker.tsx index 4532214c9260f..2dbc8142e6dbd 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/design-setup/unified-design-picker.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/design-setup/unified-design-picker.tsx @@ -52,7 +52,7 @@ import UpgradeModal from './upgrade-modal'; import getThemeIdFromDesign from './utils/get-theme-id-from-design'; import type { Step, ProvidedDependencies } from '../../types'; import './style.scss'; -import type { StarterDesigns } from '@automattic/data-stores'; +import type { OnboardSelect, SiteSelect, StarterDesigns } from '@automattic/data-stores'; import type { Design, StyleVariation } from '@automattic/design-picker'; const SiteIntent = Onboard.SiteIntent; @@ -69,7 +69,10 @@ const UnifiedDesignPickerStep: Step = ( { navigation, flow } ) => { const isMobile = ! useViewportMatch( 'small' ); const isXLargeScreen = useMediaQuery( '(min-width: 1080px)' ); - const intent = useSelect( ( select ) => select( ONBOARD_STORE ).getIntent() ); + const intent = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getIntent(), + [] + ); const site = useSite(); const siteSlug = useSiteSlugParam(); @@ -78,11 +81,16 @@ const UnifiedDesignPickerStep: Step = ( { navigation, flow } ) => { const siteTitle = site?.name; const siteDescription = site?.description; const siteVerticalId = useSelect( - ( select ) => ( site && select( SITE_STORE ).getSiteVerticalId( site.ID ) ) || '' + ( select ) => + ( site && ( select( SITE_STORE ) as SiteSelect ).getSiteVerticalId( site.ID ) ) || '', + [ site ] ); const { shouldLimitGlobalStyles } = usePremiumGlobalStyles(); - const isAtomic = useSelect( ( select ) => site && select( SITE_STORE ).isSiteAtomic( site.ID ) ); + const isAtomic = useSelect( + ( select ) => site && ( select( SITE_STORE ) as SiteSelect ).isSiteAtomic( site.ID ), + [ site ] + ); useEffect( () => { if ( isAtomic ) { exitFlow?.( `/site-editor/${ siteSlugOrId }` ); @@ -92,7 +100,12 @@ const UnifiedDesignPickerStep: Step = ( { navigation, flow } ) => { const isPremiumThemeAvailable = Boolean( useSelect( ( select ) => - site && select( SITE_STORE ).siteHasFeature( site.ID, WPCOM_FEATURES_PREMIUM_THEMES ) + site && + ( select( SITE_STORE ) as SiteSelect ).siteHasFeature( + site.ID, + WPCOM_FEATURES_PREMIUM_THEMES + ), + [ site ] ) ); @@ -175,7 +188,10 @@ const UnifiedDesignPickerStep: Step = ( { navigation, flow } ) => { window.scrollTo( { top: 0 } ); }, [ isPreviewingDesign ] ); - const selectedDesign = useSelect( ( select ) => select( ONBOARD_STORE ).getSelectedDesign() ); + const selectedDesign = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedDesign(), + [] + ); const { setSelectedDesign } = useDispatch( ONBOARD_STORE ); const selectedDesignHasStyleVariations = ( selectedDesign?.style_variations || [] ).length > 0; @@ -183,8 +199,9 @@ const UnifiedDesignPickerStep: Step = ( { navigation, flow } ) => { enabled: isPreviewingDesign && selectedDesignHasStyleVariations, } ); - const selectedStyleVariation = useSelect( ( select ) => - select( ONBOARD_STORE ).getSelectedStyleVariation() + const selectedStyleVariation = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedStyleVariation(), + [] ); const { setSelectedStyleVariation } = useDispatch( ONBOARD_STORE ); @@ -316,7 +333,8 @@ const UnifiedDesignPickerStep: Step = ( { navigation, flow } ) => { const [ showUpgradeModal, setShowUpgradeModal ] = useState( false ); const isEligibleForProPlan = useSelect( - ( select ) => site && select( SITE_STORE ).isEligibleForProPlan( site.ID ) + ( select ) => site && ( select( SITE_STORE ) as SiteSelect ).isEligibleForProPlan( site.ID ), + [ site ] ); function upgradePlan() { diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/design-setup/upgrade-modal.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/design-setup/upgrade-modal.tsx index 0fd2ebc9f333e..577793cc6da5b 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/design-setup/upgrade-modal.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/design-setup/upgrade-modal.tsx @@ -10,6 +10,7 @@ import { useThemeDetails } from 'calypso/landing/stepper/hooks/use-theme-details import { PRODUCTS_LIST_STORE } from 'calypso/landing/stepper/stores'; import ThemeFeatures from './theme-features'; import './upgrade-modal.scss'; +import type { ProductsListSelect } from '@automattic/data-stores'; interface UpgradeModalProps { /* Theme slug */ @@ -36,11 +37,15 @@ const UpgradeModal = ( { slug, isOpen, closeModal, checkout }: UpgradeModalProps const theme_software_set = theme?.data?.taxonomies?.theme_software_set?.length; const showBundleVersion = theme_software_set; - const premiumPlanProduct = useSelect( ( select ) => - select( PRODUCTS_LIST_STORE ).getProductBySlug( 'value_bundle' ) + const premiumPlanProduct = useSelect( + ( select ) => + ( select( PRODUCTS_LIST_STORE ) as ProductsListSelect ).getProductBySlug( 'value_bundle' ), + [] ); - const businessPlanProduct = useSelect( ( select ) => - select( PRODUCTS_LIST_STORE ).getProductBySlug( 'business-bundle' ) + const businessPlanProduct = useSelect( + ( select ) => + ( select( PRODUCTS_LIST_STORE ) as ProductsListSelect ).getProductBySlug( 'business-bundle' ), + [] ); //Wait until we have theme and product data to show content diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/domains/domain-form-control.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/domains/domain-form-control.tsx index 84a49182f44eb..1d86a17cef8c6 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/domains/domain-form-control.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/domains/domain-form-control.tsx @@ -21,7 +21,7 @@ import { getAvailableProductsList } from 'calypso/state/products-list/selectors' import { getSelectedSite } from 'calypso/state/ui/selectors'; import { useQuery } from '../../../../hooks/use-query'; import { ONBOARD_STORE } from '../../../../stores'; -import type { DomainSuggestion, DomainForm } from '@automattic/data-stores'; +import type { DomainSuggestion, DomainForm, OnboardSelect } from '@automattic/data-stores'; interface DomainFormControlProps { analyticsSection: string; @@ -51,10 +51,13 @@ export function DomainFormControl( { }; } ); - const { domainForm, siteTitle } = useSelect( ( select ) => ( { - domainForm: select( ONBOARD_STORE ).getDomainForm(), - siteTitle: select( ONBOARD_STORE ).getSelectedSiteTitle(), - } ) ); + const { domainForm, siteTitle } = useSelect( + ( select ) => ( { + domainForm: ( select( ONBOARD_STORE ) as OnboardSelect ).getDomainForm(), + siteTitle: ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedSiteTitle(), + } ), + [] + ); const { setDomainForm } = useDispatch( ONBOARD_STORE ); diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/edit-email/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/edit-email/index.tsx index 433c128a63f84..e85e35981224f 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/edit-email/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/edit-email/index.tsx @@ -14,16 +14,23 @@ import { recordTracksEvent } from 'calypso/lib/analytics/tracks'; import wpcom from 'calypso/lib/wp'; import { ActionSection, StyledNextButton } from 'calypso/signup/steps/woocommerce-install'; import type { Step } from '../../types'; +import type { OnboardSelect } from '@automattic/data-stores'; import './style.scss'; type FormFields = 'email' | 'password'; const EditEmail: Step = function EditEmail( { navigation } ) { const { goBack, submit } = navigation; - const intent = useSelect( ( select ) => select( ONBOARD_STORE ).getIntent() ); + const intent = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getIntent(), + [] + ); const { __ } = useI18n(); const [ errors, setErrors ] = useState( {} as Record< FormFields, string > ); - const stepProgress = useSelect( ( select ) => select( ONBOARD_STORE ).getStepProgress() ); + const stepProgress = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getStepProgress(), + [] + ); const { setEditEmail } = useDispatch( ONBOARD_STORE ); const [ email, setEmail ] = useState( '' ); const [ sendError, setSendError ] = useState( '' ); diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/free-setup/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/free-setup/index.tsx index 5c272f340249a..38747fdfb441b 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/free-setup/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/free-setup/index.tsx @@ -10,6 +10,7 @@ import { clearSignupDestinationCookie } from 'calypso/signup/storageUtils'; import { useSite } from '../../../../hooks/use-site'; import SetupForm from '../components/setup-form'; import type { Step } from '../../types'; +import type { OnboardSelect } from '@automattic/data-stores'; import './styles.scss'; @@ -31,7 +32,7 @@ const FreeSetup: Step = function FreeSetup( { navigation } ) { const [ siteTitle, setComponentSiteTitle ] = React.useState( '' ); const [ tagline, setTagline ] = React.useState( '' ); const { setSiteTitle, setSiteDescription, setSiteLogo } = useDispatch( ONBOARD_STORE ); - const state = useSelect( ( select ) => select( ONBOARD_STORE ) ).getState(); + const state = useSelect( ( select ) => select( ONBOARD_STORE ) as OnboardSelect, [] ).getState(); useEffect( () => { clearSignupDestinationCookie(); diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/goals/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/goals/index.tsx index 94472122ec04e..9538eb335284d 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/goals/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/goals/index.tsx @@ -9,6 +9,7 @@ import { getQueryArgs } from 'calypso/lib/query-args'; import { GoalsCaptureContainer } from './goals-capture-container'; import SelectGoals from './select-goals'; import type { Step } from '../../types'; +import type { OnboardSelect } from '@automattic/data-stores'; import './style.scss'; type TracksGoalsSelectEventProperties = { @@ -41,7 +42,10 @@ const GoalsStep: Step = ( { navigation } ) => { const whatAreYourGoalsText = translate( 'What are your goals?' ); const subHeaderText = translate( 'Tell us what would you like to accomplish with your website.' ); - const goals = useSelect( ( select ) => select( ONBOARD_STORE ).getGoals() ); + const goals = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getGoals(), + [] + ); const { setGoals, setIntent, resetIntent } = useDispatch( ONBOARD_STORE ); const refParameter = getQueryArgs()?.ref as string; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/import-light/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/import-light/index.tsx index 041d6789b3069..d0182eb41b6b7 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/import-light/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/import-light/index.tsx @@ -15,6 +15,7 @@ import { useSiteSlugParam } from 'calypso/landing/stepper/hooks/use-site-slug-pa import { ANALYZER_STORE } from 'calypso/landing/stepper/stores'; import { recordTracksEvent } from 'calypso/lib/analytics/tracks'; import type { ProgressState } from './types'; +import type { AnalyzerSelect } from '@automattic/data-stores'; import type { Step } from 'calypso/landing/stepper/declarative-flow/internals/types'; import './style.scss'; @@ -27,9 +28,13 @@ const ImportLight: Step = function ImportStep( props ) { const [ progressState, setProgressState ] = useState< ProgressState >( 'capture' ); const [ percentage, setPercentage ] = useState( 2 ); const { analyzeColors } = useDispatch( ANALYZER_STORE ); - const colorsData = useSelect( ( select ) => select( ANALYZER_STORE ).getSiteColors( url ) ); - const fetchingColorsInProgress = useSelect( ( select ) => - select( ANALYZER_STORE ).isSiteColorsInAnalysis() + const colorsData = useSelect( + ( select ) => ( select( ANALYZER_STORE ) as AnalyzerSelect ).getSiteColors( url ), + [ url ] + ); + const fetchingColorsInProgress = useSelect( + ( select ) => ( select( ANALYZER_STORE ) as AnalyzerSelect ).isSiteColorsInAnalysis(), + [] ); useEffect( () => { diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/importer/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/importer/index.tsx index cb25fe73003e0..24e61ce207d5f 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/importer/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/importer/index.tsx @@ -33,6 +33,7 @@ import { useAtomicTransferQueryParamUpdate } from './hooks/use-atomic-transfer-q import { useInitialQueryRun } from './hooks/use-initial-query-run'; import { useStepNavigator } from './hooks/use-step-navigator'; import type { ImporterCompType } from './types'; +import type { OnboardSelect } from '@automattic/data-stores'; interface Props { importer: Importer; @@ -58,7 +59,10 @@ export function withImporterWrapper( Importer: ImporterCompType ) { const siteImports = useSelector( ( state ) => getImporterStatusForSiteId( state, siteId ) ); const hasAllSitesFetched = useSelector( ( state ) => hasAllSitesList( state ) ); const isImporterStatusHydrated = useSelector( isImporterStatusHydratedSelector ); - const isMigrateFromWp = useSelect( ( select ) => select( ONBOARD_STORE ).getIsMigrateFromWp() ); + const isMigrateFromWp = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getIsMigrateFromWp(), + [] + ); const fromSite = currentSearchParams.get( 'from' ) || ''; const fromSiteData = useSelector( getUrlData ); diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/launchpad/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/launchpad/index.tsx index 97dc26c694cd0..46d754ac425b8 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/launchpad/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/launchpad/index.tsx @@ -16,6 +16,7 @@ import { successNotice } from 'calypso/state/notices/actions'; import { useQuery } from '../../../../hooks/use-query'; import StepContent from './step-content'; import type { Step } from '../../types'; +import type { SiteSelect } from '@automattic/data-stores'; import './style.scss'; @@ -35,7 +36,10 @@ const Launchpad: Step = ( { navigation, flow }: LaunchpadProps ) => { const dispatch = useDispatch(); const isLoggedIn = useSelector( isUserLoggedIn ); - const fetchingSiteError = useSelect( ( select ) => select( SITE_STORE ).getFetchingSiteError() ); + const fetchingSiteError = useSelect( + ( select ) => ( select( SITE_STORE ) as SiteSelect ).getFetchingSiteError(), + [] + ); if ( ! isLoggedIn ) { window.location.replace( `/home/${ siteSlug }` ); diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/launchpad/sidebar.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/launchpad/sidebar.tsx index 15aedb99f5e73..3ababcc1063a6 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/launchpad/sidebar.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/launchpad/sidebar.tsx @@ -73,7 +73,7 @@ const Sidebar = ( { sidebarDomain, siteSlug, submit, goNext, goToStep, flow }: S isEmailVerified ); - const enhancedTasks = + const enhancedTasks: Task[] | null = site && getEnhancedTasks( arrayOfFilteredTasks, diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/launchpad/step-content.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/launchpad/step-content.tsx index 19ee47ea1c089..bc2496d3ec9cf 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/launchpad/step-content.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/launchpad/step-content.tsx @@ -15,6 +15,7 @@ import { createSiteDomainObject } from 'calypso/state/sites/domains/assembler'; import EmailValidationBanner from './email-validation-banner'; import LaunchpadSitePreview from './launchpad-site-preview'; import Sidebar from './sidebar'; +import type { SiteSelect } from '@automattic/data-stores'; type StepContentProps = { siteSlug: string | null; @@ -31,7 +32,9 @@ function sortByRegistrationDate( domainObjectA: ResponseDomain, domainObjectB: R const StepContent = ( { siteSlug, submit, goNext, goToStep, flow }: StepContentProps ) => { const site = useSite(); const adminUrl = useSelect( - ( select ) => site && select( SITE_STORE ).getSiteOption( site.ID, 'admin_url' ) + ( select ) => + site && ( select( SITE_STORE ) as SiteSelect ).getSiteOption( site.ID, 'admin_url' ), + [ site ] ); const { data: allDomains = [] } = useGetDomainsQuery( site?.ID ?? null, { retry: false, diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/launchpad/task-helper.ts b/client/landing/stepper/declarative-flow/internals/steps-repository/launchpad/task-helper.ts index 6bdf1b7310fd7..40764cf9e8dbb 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/launchpad/task-helper.ts +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/launchpad/task-helper.ts @@ -10,13 +10,13 @@ import { __ } from '@wordpress/i18n'; import { addQueryArgs } from '@wordpress/url'; import { translate } from 'i18n-calypso'; import { PLANS_LIST } from 'calypso/../packages/calypso-products/src/plans-list'; -import { SiteDetails } from 'calypso/../packages/data-stores/src'; import { NavigationControls } from 'calypso/landing/stepper/declarative-flow/internals/types'; import { recordTracksEvent } from 'calypso/lib/analytics/tracks'; import { isVideoPressFlow } from 'calypso/signup/utils'; import { ONBOARD_STORE, SITE_STORE } from '../../../../stores'; import { launchpadFlowTasks } from './tasks'; import { Task } from './types'; +import type { SiteDetails } from '@automattic/data-stores'; export function getEnhancedTasks( tasks: Task[] | null, diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/link-in-bio-setup/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/link-in-bio-setup/index.tsx index 828256f44defb..a479a1b6f7572 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/link-in-bio-setup/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/link-in-bio-setup/index.tsx @@ -9,6 +9,7 @@ import { recordTracksEvent } from 'calypso/lib/analytics/tracks'; import { useSite } from '../../../../hooks/use-site'; import SetupForm from '../components/setup-form'; import type { Step } from '../../types'; +import type { OnboardSelect } from '@automattic/data-stores'; import './styles.scss'; @@ -30,7 +31,7 @@ const LinkInBioSetup: Step = function LinkInBioSetup( { navigation } ) { const [ siteTitle, setComponentSiteTitle ] = React.useState( '' ); const [ tagline, setTagline ] = React.useState( '' ); const { setSiteTitle, setSiteDescription, setSiteLogo } = useDispatch( ONBOARD_STORE ); - const state = useSelect( ( select ) => select( ONBOARD_STORE ) ).getState(); + const state = useSelect( ( select ) => select( ONBOARD_STORE ) as OnboardSelect, [] ).getState(); useEffect( () => { const { siteTitle, siteDescription, siteLogo } = state; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/login/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/login/index.tsx index bbf2076bec905..6986717fccb7c 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/login/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/login/index.tsx @@ -22,14 +22,21 @@ import { useIsAnchorFm } from 'calypso/landing/stepper/hooks/use-is-anchor-fm'; import { ONBOARD_STORE, USER_STORE, SITE_STORE } from 'calypso/landing/stepper/stores'; import { recordTracksEvent } from 'calypso/lib/analytics/tracks'; import type { Step } from '../../types'; +import type { UserSelect } from '@automattic/data-stores'; import type { FormEvent } from 'react'; import './style.scss'; const LoginStep: Step = function LoginStep( { navigation } ) { const { submit, goToStep } = navigation; const { __ } = useI18n(); - const currentUser = useSelect( ( select ) => select( USER_STORE ).getCurrentUser() ); - const userIsLoggedIn = useSelect( ( select ) => select( USER_STORE ).isCurrentUserLoggedIn() ); + const currentUser = useSelect( + ( select ) => ( select( USER_STORE ) as UserSelect ).getCurrentUser(), + [] + ); + const userIsLoggedIn = useSelect( + ( select ) => ( select( USER_STORE ) as UserSelect ).isCurrentUserLoggedIn(), + [] + ); //Check to see if there is a site with a matching anchor podcast ID const isLookingUpMatchingAnchorSites = useDetectMatchingAnchorSite(); const { setSiteSetupError } = useDispatch( SITE_STORE ); @@ -38,8 +45,14 @@ const LoginStep: Step = function LoginStep( { navigation } ) { const { isAnchorFmPodcastIdError } = useAnchorFmParams(); const [ recaptchaClientId, setRecaptchaClientId ] = useState< number >(); const { createAccount } = useDispatch( USER_STORE ); - const isFetchingNewUser = useSelect( ( select ) => select( USER_STORE ).isFetchingNewUser() ); - const newUserError = useSelect( ( select ) => select( USER_STORE ).getNewUserError() ); + const isFetchingNewUser = useSelect( + ( select ) => ( select( USER_STORE ) as UserSelect ).isFetchingNewUser(), + [] + ); + const newUserError = useSelect( + ( select ) => ( select( USER_STORE ) as UserSelect ).getNewUserError(), + [] + ); const lang = useLangRouteParam(); const isMobile = useViewportMatch( 'small', '<' ); const { anchorFmPodcastId, anchorFmEpisodeId, anchorFmSpotifyUrl } = useAnchorFmParams(); diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/migration-handler/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/migration-handler/index.tsx index 1b8a2b5f6febf..e1a3b516cabb3 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/migration-handler/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/migration-handler/index.tsx @@ -9,12 +9,16 @@ import { useSiteQuery } from 'calypso/data/sites/use-site-query'; import { ONBOARD_STORE } from 'calypso/landing/stepper/stores'; import { recordTracksEvent } from 'calypso/lib/analytics/tracks'; import type { Step } from '../../types'; +import type { OnboardSelect } from '@automattic/data-stores'; import './styles.scss'; const MigrationHandler: Step = function MigrationHandler( { navigation } ) { const { submit } = navigation; const { __ } = useI18n(); - const stepProgress = useSelect( ( select ) => select( ONBOARD_STORE ).getStepProgress() ); + const stepProgress = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getStepProgress(), + [] + ); const { setIsMigrateFromWp } = useDispatch( ONBOARD_STORE ); const search = window.location.search; const sourceSiteSlug = new URLSearchParams( search ).get( 'from' ) || ''; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/newsletter-setup/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/newsletter-setup/index.tsx index 753aa693c54f0..a12d2f87a56ac 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/newsletter-setup/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/newsletter-setup/index.tsx @@ -12,6 +12,7 @@ import { useSite } from '../../../../hooks/use-site'; import AccentColorControl, { AccentColor } from '../components/accent-color-control'; import SetupForm from '../components/setup-form'; import type { Step } from '../../types'; +import type { OnboardSelect } from '@automattic/data-stores'; import './style.scss'; export const defaultAccentColor = { @@ -46,7 +47,7 @@ const NewsletterSetup: Step = ( { navigation } ) => { const [ accentColor, setAccentColor ] = useState< AccentColor >( defaultAccentColor ); const [ base64Image, setBase64Image ] = useState< string | null >(); const [ selectedFile, setSelectedFile ] = useState< File | undefined >(); - const state = useSelect( ( select ) => select( ONBOARD_STORE ) ).getState(); + const state = useSelect( ( select ) => select( ONBOARD_STORE ) as OnboardSelect, [] ).getState(); useEffect( () => { const { siteAccentColor, siteTitle, siteDescription, siteLogo } = state; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/index.tsx index 3eb09a8f4f35e..adafa9232df3b 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/index.tsx @@ -35,6 +35,7 @@ import { encodePatternId } from './utils'; import withGlobalStylesProvider from './with-global-styles-provider'; import type { Pattern } from './types'; import type { Step } from '../../types'; +import type { OnboardSelect } from '@automattic/data-stores'; import type { DesignRecipe, Design } from '@automattic/design-picker/src/types'; import type { GlobalStylesObject } from '@automattic/global-styles'; import './style.scss'; @@ -52,8 +53,14 @@ const PatternAssembler: Step = ( { navigation, flow, stepName } ) => { const { applyThemeWithPatterns } = useDispatch( SITE_STORE ); const reduxDispatch = useReduxDispatch(); const { setPendingAction } = useDispatch( ONBOARD_STORE ); - const selectedDesign = useSelect( ( select ) => select( ONBOARD_STORE ).getSelectedDesign() ); - const intent = useSelect( ( select ) => select( ONBOARD_STORE ).getIntent() ); + const selectedDesign = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedDesign(), + [] + ); + const intent = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getIntent(), + [] + ); const site = useSite(); const siteSlug = useSiteSlugParam(); const siteId = useSiteIdParam(); diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/with-global-styles-provider.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/with-global-styles-provider.tsx index a8d36710b41ca..85abec7ac1a7c 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/with-global-styles-provider.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/with-global-styles-provider.tsx @@ -6,11 +6,15 @@ import { useSiteIdParam } from '../../../../hooks/use-site-id-param'; import { useSiteSlugParam } from '../../../../hooks/use-site-slug-param'; import { ONBOARD_STORE } from '../../../../stores'; import StepperLoader from '../../components/stepper-loader'; +import type { OnboardSelect } from '@automattic/data-stores'; const withGlobalStylesProvider = createHigherOrderComponent( < OuterProps, >( InnerComponent: React.ComponentType< OuterProps > ) => { return ( props: OuterProps ) => { - const selectedDesign = useSelect( ( select ) => select( ONBOARD_STORE ).getSelectedDesign() ); + const selectedDesign = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedDesign(), + [] + ); const siteSlug = useSiteSlugParam(); const siteId = useSiteIdParam(); const siteSlugOrId = siteSlug ? siteSlug : siteId; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/plans/plans-wrapper.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/plans/plans-wrapper.tsx index 155d9d5c3efda..a724804e7901f 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/plans/plans-wrapper.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/plans/plans-wrapper.tsx @@ -18,6 +18,7 @@ import StepWrapper from 'calypso/signup/step-wrapper'; import { recordTracksEvent } from 'calypso/state/analytics/actions'; import { getPlanSlug } from 'calypso/state/plans/selectors'; import { ONBOARD_STORE } from '../../../../stores'; +import type { OnboardSelect } from '@automattic/data-stores'; import './style.scss'; type IntervalType = 'yearly' | 'monthly'; @@ -30,10 +31,10 @@ interface Props { const PlansWrapper: React.FC< Props > = ( props ) => { const { hideFreePlan, domainCartItem } = useSelect( ( select ) => { return { - hideFreePlan: select( ONBOARD_STORE ).getHideFreePlan(), - domainCartItem: select( ONBOARD_STORE ).getDomainCartItem(), + hideFreePlan: ( select( ONBOARD_STORE ) as OnboardSelect ).getHideFreePlan(), + domainCartItem: ( select( ONBOARD_STORE ) as OnboardSelect ).getDomainCartItem(), }; - } ); + }, [] ); const { setPlanCartItem } = useDispatch( ONBOARD_STORE ); diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/podcast-title/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/podcast-title/index.tsx index 4f7d3daccc408..199583fd6098f 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/podcast-title/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/podcast-title/index.tsx @@ -15,6 +15,7 @@ import { ONBOARD_STORE, USER_STORE } from 'calypso/landing/stepper/stores'; import { recordTracksEvent } from 'calypso/lib/analytics/tracks'; import { tip } from 'calypso/signup/icons'; import type { Step } from '../../types'; +import type { OnboardSelect, UserSelect } from '@automattic/data-stores'; import './style.scss'; const PodcastTitleStep: Step = function PodcastTitleStep( { navigation } ) { @@ -24,9 +25,18 @@ const PodcastTitleStep: Step = function PodcastTitleStep( { navigation } ) { const PodcastTitleForm: React.FC = () => { //Get the podcast title from the API const podcastTitle = usePodcastTitle(); - const { siteTitle } = useSelect( ( select ) => select( ONBOARD_STORE ).getState() ); - const currentUser = useSelect( ( select ) => select( USER_STORE ).getCurrentUser() ); - const newUser = useSelect( ( select ) => select( USER_STORE ).getNewUser() ); + const { siteTitle } = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getState(), + [] + ); + const currentUser = useSelect( + ( select ) => ( select( USER_STORE ) as UserSelect ).getCurrentUser(), + [] + ); + const newUser = useSelect( + ( select ) => ( select( USER_STORE ) as UserSelect ).getNewUser(), + [] + ); const hasSiteTitle = siteTitle.length > 0; const { setSiteTitle } = useDispatch( ONBOARD_STORE ); const [ formTouched, setFormTouched ] = useState( false ); diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/processing-step/hooks/use-processing-loading-messages.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/processing-step/hooks/use-processing-loading-messages.tsx index bdb8a61f4890e..4f7c51cfd51c9 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/processing-step/hooks/use-processing-loading-messages.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/processing-step/hooks/use-processing-loading-messages.tsx @@ -5,6 +5,7 @@ import { useI18n } from '@wordpress/react-i18n'; import WooPurpleHeart from 'calypso/assets/images/onboarding/woo-purple-heart.png'; import { STEPPER_INTERNAL_STORE } from 'calypso/landing/stepper/stores'; import type { LoadingMessage } from './types'; +import type { StepperInternalSelect } from '@automattic/data-stores'; const SiteIntent = Onboard.SiteIntent; @@ -12,7 +13,10 @@ export function useProcessingLoadingMessages( flow?: string | null ): LoadingMes const { __ } = useI18n(); let loadingMessages = []; - const stepData = useSelect( ( select ) => select( STEPPER_INTERNAL_STORE ).getStepData() ); + const stepData = useSelect( + ( select ) => ( select( STEPPER_INTERNAL_STORE ) as StepperInternalSelect ).getStepData(), + [] + ); if ( flow === 'copy-site' ) { return [ diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/processing-step/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/processing-step/index.tsx index 0e3529212cda6..21a2723d10058 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/processing-step/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/processing-step/index.tsx @@ -21,6 +21,7 @@ import { useProcessingLoadingMessages } from './hooks/use-processing-loading-mes import { useVideoPressLoadingMessages } from './hooks/use-videopress-loading-messages'; import TailoredFlowPreCheckoutScreen from './tailored-flow-precheckout-screen'; import type { StepProps } from '../../types'; +import type { OnboardSelect } from '@automattic/data-stores'; import './style.scss'; export enum ProcessingResult { @@ -52,10 +53,22 @@ const ProcessingStep: React.FC< ProcessingStepProps > = function ( props ) { setCurrentMessageIndex( ( s ) => ( s + 1 ) % loadingMessages.length ); }, loadingMessages[ currentMessageIndex ]?.duration ); - const action = useSelect( ( select ) => select( ONBOARD_STORE ).getPendingAction() ); - const progress = useSelect( ( select ) => select( ONBOARD_STORE ).getProgress() ); - const progressTitle = useSelect( ( select ) => select( ONBOARD_STORE ).getProgressTitle() ); - const stepProgress = useSelect( ( select ) => select( ONBOARD_STORE ).getStepProgress() ); + const action = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getPendingAction(), + [] + ); + const progress = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getProgress(), + [] + ); + const progressTitle = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getProgressTitle(), + [] + ); + const stepProgress = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getStepProgress(), + [] + ); const getCurrentMessage = () => { return props.title || progressTitle || loadingMessages[ currentMessageIndex ]?.title; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/sensei-domain/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/sensei-domain/index.tsx index b278c98d947e3..4b487ab2bf73e 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/sensei-domain/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/sensei-domain/index.tsx @@ -9,19 +9,21 @@ import { recordTracksEvent } from 'calypso/lib/analytics/tracks'; import CalypsoShoppingCartProvider from 'calypso/my-sites/checkout/calypso-shopping-cart-provider'; import { SenseiStepContainer } from '../components/sensei-step-container'; import type { Step } from '../../types'; +import type { OnboardSelect, ProductsListSelect } from '@automattic/data-stores'; import './style.scss'; const SenseiDomain: Step = ( { navigation } ) => { const { submit } = navigation; const { __ } = useI18n(); - const [ siteTitle, domain, productsList ] = useSelect( ( select ) => { - return [ - select( ONBOARD_STORE ).getSelectedSiteTitle(), - select( ONBOARD_STORE ).getSelectedDomain(), - select( PRODUCTS_LIST_STORE ).getProductsList(), - ]; - } ); + const { siteTitle, domain, productsList } = useSelect( + ( select ) => ( { + siteTitle: ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedSiteTitle(), + domain: ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedDomain(), + productsList: ( select( PRODUCTS_LIST_STORE ) as ProductsListSelect ).getProductsList(), + } ), + [] + ); const { setDomain } = useDispatch( ONBOARD_STORE ); const onSkip = () => { diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/sensei-plan/create-sensei-site.ts b/client/landing/stepper/declarative-flow/internals/steps-repository/sensei-plan/create-sensei-site.ts index 2bf427e883e44..6b28ddf962c12 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/sensei-plan/create-sensei-site.ts +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/sensei-plan/create-sensei-site.ts @@ -7,6 +7,7 @@ import { useNewSiteVisibility } from 'calypso/landing/gutenboarding/hooks/use-se import { ONBOARD_STORE, SITE_STORE, USER_STORE } from 'calypso/landing/stepper/stores'; import wpcom from 'calypso/lib/wp'; import { Progress } from '../components/sensei-step-progress'; +import type { OnboardSelect, SiteSelect, UserSelect } from '@automattic/data-stores'; import type { StyleVariation } from 'calypso/../packages/design-picker'; const getStyleVariations = ( siteId: number, stylesheet: string ): Promise< StyleVariation[] > => @@ -40,11 +41,17 @@ const updateGlobalStyles = ( const COURSE_THEME = 'pub/course'; export const useCreateSenseiSite = () => { - const { getNewSite } = useSelect( ( select ) => select( SITE_STORE ) ); + const { getNewSite } = useSelect( ( select ) => select( SITE_STORE ) as SiteSelect, [] ); const { setIntentOnSite, saveSiteSettings } = useDispatch( SITE_STORE ); - const currentUser = useSelect( ( select ) => select( USER_STORE ).getCurrentUser() ); + const currentUser = useSelect( + ( select ) => ( select( USER_STORE ) as UserSelect ).getCurrentUser(), + [] + ); const { createSenseiSite, setSelectedSite } = useDispatch( ONBOARD_STORE ); - const { getSelectedStyleVariation } = useSelect( ( select ) => select( ONBOARD_STORE ) ); + const { getSelectedStyleVariation } = useSelect( + ( select ) => select( ONBOARD_STORE ) as OnboardSelect, + [] + ); const [ progress, setProgress ] = useState< Progress >( { percentage: 0, diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/sensei-plan/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/sensei-plan/index.tsx index a9531d20a002d..9dde1c7a7b978 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/sensei-plan/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/sensei-plan/index.tsx @@ -20,6 +20,7 @@ import { features, Status } from './constants'; import { useCreateSenseiSite } from './create-sensei-site'; import { useBusinessPlanPricing, useSenseiProPricing } from './sensei-plan-products'; import type { Step } from '../../types'; +import type { OnboardSelect } from '@automattic/data-stores'; import type { PlanBillingPeriod } from 'calypso/../packages/data-stores'; import 'calypso/../packages/plans-grid/src/plans-table/style.scss'; @@ -31,7 +32,10 @@ const SenseiPlan: Step = ( { flow, navigation: { submit } } ) => { const locale = useLocale(); const { hasTranslation } = useI18n(); - const domain = useSelect( ( select ) => select( ONBOARD_STORE ).getSelectedDomain() ); + const domain = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedDomain(), + [] + ); const senseiProPlan = useSenseiProPricing( billingPeriod ); const businessPlan = useBusinessPlanPricing( billingPeriod ); diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/sensei-plan/sensei-plan-products.ts b/client/landing/stepper/declarative-flow/internals/steps-repository/sensei-plan/sensei-plan-products.ts index ae7663d73c5b5..ccb5928eed565 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/sensei-plan/sensei-plan-products.ts +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/sensei-plan/sensei-plan-products.ts @@ -3,7 +3,11 @@ import { useSelect } from '@wordpress/data'; import { useSupportedPlans } from 'calypso/../packages/plans-grid/src/hooks'; import { PLANS_STORE } from 'calypso/landing/gutenboarding/stores/plans'; import { PRODUCTS_LIST_STORE } from 'calypso/landing/stepper/stores'; -import type { PlanBillingPeriod } from 'calypso/../packages/data-stores'; +import type { + PlanBillingPeriod, + PlansSelect, + ProductsListSelect, +} from 'calypso/../packages/data-stores'; const SENSEI_PRO_PRODUCT_YEARLY = 'sensei_pro_yearly'; const SENSEI_PRO_PRODUCT_MONTHLY = 'sensei_pro_monthly'; @@ -12,7 +16,7 @@ export function useSenseiProPricing( billingPeriod: PlanBillingPeriod ) { return useSelect( ( select ) => { const isYearly = billingPeriod === 'ANNUALLY'; - const { getProductBySlug } = select( PRODUCTS_LIST_STORE ); + const { getProductBySlug }: ProductsListSelect = select( PRODUCTS_LIST_STORE ); const yearly = getProductBySlug( SENSEI_PRO_PRODUCT_YEARLY ); const monthly = getProductBySlug( SENSEI_PRO_PRODUCT_MONTHLY ); @@ -50,7 +54,7 @@ export function useBusinessPlanPricing( billingPeriod: PlanBillingPeriod ) { return useSelect( ( select ) => { - const { getPlanProduct } = select( PLANS_STORE ); + const { getPlanProduct }: PlansSelect = select( PLANS_STORE ); const monthly = getPlanProduct( slug, 'MONTHLY' ); const yearly = getPlanProduct( slug, 'ANNUALLY' ); diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/sensei-setup/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/sensei-setup/index.tsx index 7a4ee499c217b..f4623312f3644 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/sensei-setup/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/sensei-setup/index.tsx @@ -11,6 +11,7 @@ import { preventWidows } from 'calypso/lib/formatting'; import { ONBOARD_STORE } from '../../../../stores'; import { SenseiStepContainer } from '../components/sensei-step-container'; import { Title, Label, Input, Hint } from './components'; +import type { OnboardSelect } from '@automattic/data-stores'; import type { StyleVariation } from 'calypso/../packages/design-picker/src/types'; import type { Step } from 'calypso/landing/stepper/declarative-flow/internals/types'; import './style.scss'; @@ -58,8 +59,9 @@ const SenseiSetup: Step = ( { navigation } ) => { const { __ } = useI18n(); const isDesktop = useDesktopBreakpoint(); - const initialSiteTitle = useSelect( ( select ) => - select( ONBOARD_STORE ).getSelectedSiteTitle() + const initialSiteTitle = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedSiteTitle(), + [] ); const [ siteTitle, setSiteTitle ] = useState< string >( initialSiteTitle ); const [ checked, setChecked ] = useState< string >( 'green' ); diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/set-theme-step/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/set-theme-step/index.tsx index ddb3a88fcdeb6..34284e9b50c46 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/set-theme-step/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/set-theme-step/index.tsx @@ -7,6 +7,7 @@ import { ONBOARD_STORE, SITE_STORE } from 'calypso/landing/stepper/stores'; import { reduxDispatch } from 'calypso/lib/redux-bridge'; import { requestActiveTheme } from 'calypso/state/themes/actions'; import type { Step } from '../../types'; +import type { OnboardSelect } from '@automattic/data-stores'; const SetThemeStep: Step = function SetThemeStep( { navigation } ) { const { submit } = navigation; @@ -16,7 +17,10 @@ const SetThemeStep: Step = function SetThemeStep( { navigation } ) { const siteId = useSite()?.ID; const siteSlug = useSiteSlugParam() || ''; - const selectedDesign = useSelect( ( select ) => select( ONBOARD_STORE ).getSelectedDesign() ); + const selectedDesign = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedDesign(), + [] + ); const themeParam = useThemeParam(); useEffect( () => { diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/site-creation-step/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/site-creation-step/index.tsx index c989c9b07aeb3..740c5c6f21dac 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/site-creation-step/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/site-creation-step/index.tsx @@ -31,6 +31,7 @@ import { } from 'calypso/signup/storageUtils'; import { getCurrentUserName } from 'calypso/state/current-user/selectors'; import type { Step } from '../../types'; +import type { OnboardSelect } from '@automattic/data-stores'; import './styles.scss'; @@ -42,16 +43,22 @@ const DEFAULT_NEWSLETTER_THEME = 'pub/lettre'; const SiteCreationStep: Step = function SiteCreationStep( { navigation, flow, data } ) { const { submit } = navigation; const { __ } = useI18n(); - const stepProgress = useSelect( ( select ) => select( ONBOARD_STORE ).getStepProgress() ); + const stepProgress = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getStepProgress(), + [] + ); const { domainCartItem, planCartItem, siteAccentColor, getSelectedSiteTitle, productCartItems } = - useSelect( ( select ) => ( { - domainCartItem: select( ONBOARD_STORE ).getDomainCartItem(), - siteAccentColor: select( ONBOARD_STORE ).getSelectedSiteAccentColor(), - planCartItem: select( ONBOARD_STORE ).getPlanCartItem(), - productCartItems: select( ONBOARD_STORE ).getProductCartItems(), - getSelectedSiteTitle: select( ONBOARD_STORE ).getSelectedSiteTitle(), - } ) ); + useSelect( + ( select ) => ( { + domainCartItem: ( select( ONBOARD_STORE ) as OnboardSelect ).getDomainCartItem(), + siteAccentColor: ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedSiteAccentColor(), + planCartItem: ( select( ONBOARD_STORE ) as OnboardSelect ).getPlanCartItem(), + productCartItems: ( select( ONBOARD_STORE ) as OnboardSelect ).getProductCartItems(), + getSelectedSiteTitle: ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedSiteTitle(), + } ), + [] + ); const username = useSelector( ( state ) => getCurrentUserName( state ) ); @@ -67,7 +74,10 @@ const SiteCreationStep: Step = function SiteCreationStep( { navigation, flow, da } const isPaidDomainItem = Boolean( domainCartItem?.product_slug ); - const progress = useSelect( ( select ) => select( ONBOARD_STORE ).getProgress() ); + const progress = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getProgress(), + [] + ); const { setProgress } = useDispatch( ONBOARD_STORE ); // Default visibility is public diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/site-options/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/site-options/index.tsx index a6c27deae238a..1bd05246a9859 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/site-options/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/site-options/index.tsx @@ -19,21 +19,26 @@ import { tip } from 'calypso/signup/icons'; import { useSite } from '../../../../hooks/use-site'; import { ONBOARD_STORE, SITE_STORE } from '../../../../stores'; import type { Step } from '../../types'; +import type { OnboardSelect } from '@automattic/data-stores'; import './style.scss'; const SiteOptions: Step = function SiteOptions( { navigation, flow } ) { - const [ currentSiteTitle, currentTagling ] = useSelect( ( select ) => { - return [ - select( ONBOARD_STORE ).getSelectedSiteTitle(), - select( ONBOARD_STORE ).getSelectedSiteDescription(), - ]; - } ); + const { currentSiteTitle, currentTagling } = useSelect( + ( select ) => ( { + currentSiteTitle: ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedSiteTitle(), + currentTagling: ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedSiteDescription(), + } ), + [] + ); const { goBack, goNext, submit } = navigation; const [ siteTitle, setSiteTitle ] = React.useState( currentSiteTitle ?? '' ); const [ tagline, setTagline ] = React.useState( currentTagling ?? '' ); const [ formTouched, setFormTouched ] = React.useState( false ); - const intent = useSelect( ( select ) => select( ONBOARD_STORE ).getIntent() ); + const intent = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getIntent(), + [] + ); const translate = useTranslate(); const site = useSite(); const isVideoPressFlow = 'videopress' === flow; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/site-vertical/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/site-vertical/index.tsx index 4f066354d9444..bb128fcae2102 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/site-vertical/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/site-vertical/index.tsx @@ -12,6 +12,7 @@ import { useSite } from '../../../../hooks/use-site'; import { SITE_STORE } from '../../../../stores'; import SiteVerticalForm from './form'; import type { Step } from '../../types'; +import type { SiteSelect } from '@automattic/data-stores'; import type { Vertical } from 'calypso/components/select-vertical/types'; const SiteVertical: Step = function SiteVertical( { navigation } ) { @@ -21,7 +22,9 @@ const SiteVertical: Step = function SiteVertical( { navigation } ) { const { saveSiteSettings } = useDispatch( SITE_STORE ); const site = useSite(); const siteVertical = useSelect( - ( select ) => ( site && select( SITE_STORE ).getSiteVerticalId( site?.ID ) ) || undefined + ( select ) => + ( site && ( select( SITE_STORE ) as SiteSelect ).getSiteVerticalId( site?.ID ) ) || undefined, + [ site ] ); const translate = useTranslate(); const headerText = translate( 'What’s your website about?' ); diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/store-address/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/store-address/index.tsx index 5afcdd35fd381..d70eefe397dde 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/store-address/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/store-address/index.tsx @@ -17,6 +17,7 @@ import { ActionSection, StyledNextButton } from 'calypso/signup/steps/woocommerc import { useCountries } from '../../../../hooks/use-countries'; import SupportCard from './support-card'; import type { Step } from '../../types'; +import type { OnboardSelect, SiteSelect, UserSelect } from '@automattic/data-stores'; import './style.scss'; type FormFields = @@ -48,17 +49,28 @@ const CityZipRow = styled.div` const StoreAddress: Step = function StoreAddress( { navigation } ) { const { goNext, submit } = navigation; - const intent = useSelect( ( select ) => select( ONBOARD_STORE ).getIntent() ); + const intent = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getIntent(), + [] + ); const site = useSite(); const settings = useSelect( - ( select ) => ( site?.ID && select( SITE_STORE ).getSiteSettings( site.ID ) ) || {} + ( select ) => + ( site?.ID && ( select( SITE_STORE ) as SiteSelect ).getSiteSettings( site.ID ) ) || {}, + [ site ] + ); + const currentUser = useSelect( + ( select ) => ( select( USER_STORE ) as UserSelect ).getCurrentUser() || null, + [] ); - const currentUser = useSelect( ( select ) => select( USER_STORE ).getCurrentUser() || null ); const { data: countries } = useCountries(); const { __ } = useI18n(); const [ errors, setErrors ] = useState( {} as Record< FormFields, string > ); const { saveSiteSettings } = useDispatch( SITE_STORE ); - const stepProgress = useSelect( ( select ) => select( ONBOARD_STORE ).getStepProgress() ); + const stepProgress = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getStepProgress(), + [] + ); const [ settingChanges, setSettingChanges ] = useState< { [ key: string ]: string; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/store-profiler/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/store-profiler/index.tsx index 283e821846236..2dc6762f29917 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/store-profiler/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/store-profiler/index.tsx @@ -15,6 +15,7 @@ import { useCountriesAndStates } from 'calypso/jetpack-cloud/sections/partner-po import { recordTracksEvent } from 'calypso/lib/analytics/tracks'; import { ONBOARD_STORE, USER_STORE } from '../../../../stores'; import type { Step } from '../../types'; +import type { UserSelect } from '@automattic/data-stores'; import './style.scss'; const StoreProfiler: Step = function StoreProfiler( { navigation, flow } ) { @@ -23,8 +24,14 @@ const StoreProfiler: Step = function StoreProfiler( { navigation, flow } ) { const [ verticalId, setVerticalId ] = React.useState( '' ); const [ storeCountryCode, setStoreCountryCode ] = React.useState( '' ); const translate = useTranslate(); - const currentUser = useSelect( ( select ) => select( USER_STORE ).getCurrentUser() ); - const newUser = useSelect( ( select ) => select( USER_STORE ).getNewUser() ); + const currentUser = useSelect( + ( select ) => ( select( USER_STORE ) as UserSelect ).getCurrentUser(), + [] + ); + const newUser = useSelect( + ( select ) => ( select( USER_STORE ) as UserSelect ).getNewUser(), + [] + ); const { setSiteTitle: saveSiteTitleToStore, setVerticalId: saveVerticalIdToStore, diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/wait-for-atomic/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/wait-for-atomic/index.tsx index 362469797225d..3457fb129def2 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/wait-for-atomic/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/wait-for-atomic/index.tsx @@ -7,6 +7,7 @@ import { recordTracksEvent } from 'calypso/lib/analytics/tracks'; import { logToLogstash } from 'calypso/lib/logstash'; import { ONBOARD_STORE, SITE_STORE } from '../../../../stores'; import type { Step } from '../../types'; +import type { OnboardSelect, SiteSelect } from '@automattic/data-stores'; export interface FailureInfo { type: string; @@ -44,10 +45,11 @@ const WaitForAtomic: Step = function WaitForAtomic( { navigation, data } ) { siteId = data?.siteId as number; } - const { getSiteLatestAtomicTransfer, getSiteLatestAtomicTransferError } = useSelect( ( select ) => - select( SITE_STORE ) + const { getSiteLatestAtomicTransfer, getSiteLatestAtomicTransferError } = useSelect( + ( select ) => select( SITE_STORE ) as SiteSelect, + [] ); - const { getIntent } = useSelect( ( select ) => select( ONBOARD_STORE ) ); + const { getIntent } = useSelect( ( select ) => select( ONBOARD_STORE ) as OnboardSelect, [] ); const handleTransferFailure = ( failureInfo: FailureInfo ) => { recordTracksEvent( 'calypso_woocommerce_dashboard_snag_error', { diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/wait-for-plugin-install/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/wait-for-plugin-install/index.tsx index 6bc2877ecfd34..3bef3578d99b9 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/wait-for-plugin-install/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/wait-for-plugin-install/index.tsx @@ -6,6 +6,7 @@ import { recordTracksEvent } from 'calypso/lib/analytics/tracks'; import { logToLogstash } from 'calypso/lib/logstash'; import { ONBOARD_STORE } from '../../../../stores'; import type { Step, PluginsResponse, FailureInfo } from '../../types'; +import type { OnboardSelect } from '@automattic/data-stores'; export const installedStates = { PENDING: 'pending', @@ -18,7 +19,10 @@ const wait = ( ms: number ) => new Promise( ( res ) => setTimeout( res, ms ) ); const WaitForPluginInstall: Step = function WaitForAtomic( { navigation, data } ) { const { submit } = navigation; const { setPendingAction } = useDispatch( ONBOARD_STORE ); - const pluginsToVerify = useSelect( ( select ) => select( ONBOARD_STORE ).getPluginsToVerify() ); + const pluginsToVerify = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getPluginsToVerify(), + [] + ); const siteId = data?.siteId; const siteSlug = data?.siteSlug; diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/woo-confirm/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/woo-confirm/index.tsx index ed8151768567d..24636f2abab35 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/woo-confirm/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/woo-confirm/index.tsx @@ -22,6 +22,7 @@ import { ActionSection, StyledNextButton } from 'calypso/signup/steps/woocommerc import { eligibilityHolds as eligibilityHoldsConstants } from 'calypso/state/automated-transfer/constants'; import SupportCard from '../store-address/support-card'; import type { Step } from '../../types'; +import type { ProductsListSelect, OnboardSelect, SiteSelect } from '@automattic/data-stores'; import type { TransferEligibilityError } from '@automattic/data-stores/src/automated-transfer-eligibility/types'; import './style.scss'; @@ -45,13 +46,15 @@ const WooConfirm: Step = function WooCommerceConfirm( { navigation } ) { const { __ } = useI18n(); const site = useSite(); const siteId = site && site?.ID; - const isAtomicSite = useSelect( ( select ) => - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore Until createRegistrySelector is typed correctly - select( SITE_STORE ).isSiteAtomic( siteId ) + const isAtomicSite = useSelect( + ( select ) => siteId && ( select( SITE_STORE ) as SiteSelect ).isSiteAtomic( siteId ), + [ siteId ] ); const { requestLatestAtomicTransfer } = useDispatch( SITE_STORE ); - const stepProgress = useSelect( ( select ) => select( ONBOARD_STORE ).getStepProgress() ); + const stepProgress = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getStepProgress(), + [] + ); useEffect( () => { if ( ! siteId ) { @@ -61,38 +64,51 @@ const WooConfirm: Step = function WooCommerceConfirm( { navigation } ) { requestLatestAtomicTransfer( siteId ); }, [ requestLatestAtomicTransfer, siteId ] ); - const eligibilityHolds = useSelect( ( select ) => - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore Until createRegistrySelector is typed correctly - select( AUTOMATED_ELIGIBILITY_STORE ).getEligibilityHolds( siteId ) + const eligibilityHolds = useSelect( + ( select ) => + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore Until createRegistrySelector is typed correctly + select( AUTOMATED_ELIGIBILITY_STORE ).getEligibilityHolds( siteId ), + [ siteId ] ); - const eligibilityWarnings = useSelect( ( select ) => - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore Until createRegistrySelector is typed correctly - select( AUTOMATED_ELIGIBILITY_STORE ).getEligibilityWarnings( siteId ) + const eligibilityWarnings = useSelect( + ( select ) => + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore Until createRegistrySelector is typed correctly + select( AUTOMATED_ELIGIBILITY_STORE ).getEligibilityWarnings( siteId ), + [ siteId ] ); - const wpcomSubdomainWarning = useSelect( ( select ) => - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore Until createRegistrySelector is typed correctly - select( AUTOMATED_ELIGIBILITY_STORE ).getWpcomSubdomainWarning( siteId ) + const wpcomSubdomainWarning = useSelect( + ( select ) => + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore Until createRegistrySelector is typed correctly + select( AUTOMATED_ELIGIBILITY_STORE ).getWpcomSubdomainWarning( siteId ), + [ siteId ] ); - const warnings: any = useSelect( ( select ) => - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore Until createRegistrySelector is typed correctly - select( AUTOMATED_ELIGIBILITY_STORE ).getNonSubdomainWarnings( siteId ) + const warnings = useSelect( + ( select ) => + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore Until createRegistrySelector is typed correctly + select( AUTOMATED_ELIGIBILITY_STORE ).getNonSubdomainWarnings( siteId ), + [ siteId ] + ); + const latestAtomicTransfer = useSelect( + ( select ) => ( select( SITE_STORE ) as SiteSelect ).getSiteLatestAtomicTransfer( siteId || 0 ), + [ siteId ] ); - const latestAtomicTransfer = useSelect( ( select ) => - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore Until createRegistrySelector is typed correctly - select( SITE_STORE ).getSiteLatestAtomicTransfer( siteId || 0 ) + const latestAtomicTransferError = useSelect( + ( select ) => + ( select( SITE_STORE ) as SiteSelect ).getSiteLatestAtomicTransferError( siteId || 0 ), + [ siteId ] ); - const latestAtomicTransferError = useSelect( ( select ) => - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore Until createRegistrySelector is typed correctly - select( SITE_STORE ).getSiteLatestAtomicTransferError( siteId || 0 ) + const productsList = useSelect( + ( select ) => ( select( PRODUCTS_LIST_STORE ) as ProductsListSelect ).getProductsList(), + [] + ); + const requiresUpgrade = useSelect( + ( select ) => ( select( SITE_STORE ) as SiteSelect ).requiresUpgrade( siteId ), + [ siteId ] ); - const productsList = useSelect( ( select ) => select( PRODUCTS_LIST_STORE ).getProductsList() ); - const requiresUpgrade = useSelect( ( select ) => select( SITE_STORE ).requiresUpgrade( siteId ) ); const wpcomDomain = site?.URL?.replace( /http[s]*:\/\//, '' ); const stagingDomain = wpcomDomain?.replace( /\b\.wordpress\.com/, '.wpcomstaging.com' ) || null; @@ -102,8 +118,6 @@ const WooConfirm: Step = function WooCommerceConfirm( { navigation } ) { const upgradingPlan = productName ? productsList?.[ productName ] : null; // Filter the Woop transferring blockers. - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore Until createRegistrySelector is typed correctly const transferringBlockers = eligibilityHolds?.filter( ( hold: TransferEligibilityError ) => ! TRANSFERRING_NOT_BLOCKERS.includes( hold.code ) ); @@ -144,8 +158,6 @@ const WooConfirm: Step = function WooCommerceConfirm( { navigation } ) { * Check whether the site transferring is blocked. * True as default, meaning it's True when requesting data. */ - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore Until createRegistrySelector is typed correctly const isTransferringBlocked = latestAtomicTransfer && ( ! transferringDataIsAvailable || transferringBlockers?.length > 0 ); @@ -154,8 +166,6 @@ const WooConfirm: Step = function WooCommerceConfirm( { navigation } ) { isReadyToStart = isReadyToStart && ! isTransferringBlocked && // there is no blockers from eligibility (holds). - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore Until createRegistrySelector is typed correctly ! ( eligibilityWarnings && eligibilityWarnings?.length ); // there is no warnings from eligibility (warnings). } @@ -217,8 +227,6 @@ const WooConfirm: Step = function WooCommerceConfirm( { navigation } ) { ); } - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore Until createRegistrySelector is typed correctly if ( warnings?.length ) { return ( diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/woo-install-plugins/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/woo-install-plugins/index.tsx index e7fae8193dccf..93b9b3523bc44 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/woo-install-plugins/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/woo-install-plugins/index.tsx @@ -7,7 +7,7 @@ import { recordTracksEvent } from 'calypso/lib/analytics/tracks'; import { logToLogstash } from 'calypso/lib/logstash'; import { ONBOARD_STORE, SITE_STORE } from '../../../../stores'; import type { Step } from '../../types'; -import type { AtomicSoftwareStatus } from 'calypso/../packages/data-stores/src/site'; +import type { AtomicSoftwareStatus, OnboardSelect, SiteSelect } from '@automattic/data-stores'; const wait = ( ms: number ) => new Promise( ( res ) => setTimeout( res, ms ) ); @@ -22,10 +22,10 @@ const WooInstallPlugins: Step = function WooInstallPlugins( { navigation } ) { const { setPendingAction, setProgressTitle, setProgress } = useDispatch( ONBOARD_STORE ); const { initiateSoftwareInstall, requestAtomicSoftwareStatus } = useDispatch( SITE_STORE ); const { getAtomicSoftwareInstallError, getAtomicSoftwareStatus, getAtomicSoftwareError } = - useSelect( ( select ) => select( SITE_STORE ) ); + useSelect( ( select ) => select( SITE_STORE ) as SiteSelect, [] ); const site = useSite(); const softwareSet = 'woo-on-plans'; - const { getIntent } = useSelect( ( select ) => select( ONBOARD_STORE ) ); + const { getIntent } = useSelect( ( select ) => select( ONBOARD_STORE ) as OnboardSelect, [] ); const handleTransferFailure = ( failureInfo: FailureInfo ) => { recordTracksEvent( 'calypso_woocommerce_dashboard_snag_error', { diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/woo-transfer/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/woo-transfer/index.tsx index 667cfaf7213b2..dc5bbabb9735e 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/woo-transfer/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/woo-transfer/index.tsx @@ -7,6 +7,7 @@ import { recordTracksEvent } from 'calypso/lib/analytics/tracks'; import { logToLogstash } from 'calypso/lib/logstash'; import { ONBOARD_STORE, SITE_STORE } from '../../../../stores'; import type { Step } from '../../types'; +import type { OnboardSelect, SiteSelect } from '@automattic/data-stores'; export interface FailureInfo { type: string; @@ -46,8 +47,8 @@ const WooTransfer: Step = function WooTransfer( { navigation } ) { getSiteLatestAtomicTransferError, getAtomicSoftwareStatus, getAtomicSoftwareError, - } = useSelect( ( select ) => select( SITE_STORE ) ); - const { getIntent } = useSelect( ( select ) => select( ONBOARD_STORE ) ); + } = useSelect( ( select ) => select( SITE_STORE ) as SiteSelect, [] ); + const { getIntent } = useSelect( ( select ) => select( ONBOARD_STORE ) as OnboardSelect, [] ); const handleTransferFailure = ( failureInfo: FailureInfo ) => { recordTracksEvent( 'calypso_woocommerce_dashboard_snag_error', { diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/woo-verify-email/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/woo-verify-email/index.tsx index 0f4a31c3ca20b..92968bd9e82d7 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/woo-verify-email/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/woo-verify-email/index.tsx @@ -14,6 +14,7 @@ import { UserData } from 'calypso/lib/user/user'; import { getCurrentUser } from 'calypso/state/current-user/selectors'; import { redirect } from '../import/util'; import type { Step } from '../../types'; +import type { OnboardSelect } from '@automattic/data-stores'; import './style.scss'; const WooVerifyEmail: Step = function WooVerifyEmail( { navigation } ) { @@ -28,7 +29,10 @@ const WooVerifyEmail: Step = function WooVerifyEmail( { navigation } ) { const [ error, setError ] = useState( '' ); const sendEmail = useSendEmailVerification(); const { setEditEmail } = useDispatch( ONBOARD_STORE ); - const editEmail = useSelect( ( select ) => select( ONBOARD_STORE ).getEditEmail() ); + const editEmail = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getEditEmail(), + [] + ); const sendVerification = async () => { setEditEmail( '' ); diff --git a/client/landing/stepper/declarative-flow/link-in-bio-tld.ts b/client/landing/stepper/declarative-flow/link-in-bio-tld.ts index 3566297cc4116..e2d7ed73c8394 100644 --- a/client/landing/stepper/declarative-flow/link-in-bio-tld.ts +++ b/client/landing/stepper/declarative-flow/link-in-bio-tld.ts @@ -21,6 +21,7 @@ import PlansStep from './internals/steps-repository/plans'; import Processing from './internals/steps-repository/processing-step'; import SiteCreationStep from './internals/steps-repository/site-creation-step'; import type { Flow, ProvidedDependencies } from './internals/types'; +import type { UserSelect } from '@automattic/data-stores'; const linkInBio: Flow = { name: LINK_IN_BIO_TLD_FLOW, @@ -44,7 +45,10 @@ const linkInBio: Flow = { const { setStepProgress } = useDispatch( ONBOARD_STORE ); const flowProgress = useFlowProgress( { stepName: _currentStepSlug, flowName } ); const siteSlug = useSiteSlug(); - const userIsLoggedIn = useSelect( ( select ) => select( USER_STORE ).isCurrentUserLoggedIn() ); + const userIsLoggedIn = useSelect( + ( select ) => ( select( USER_STORE ) as UserSelect ).isCurrentUserLoggedIn(), + [] + ); const locale = useLocale(); setStepProgress( flowProgress ); diff --git a/client/landing/stepper/declarative-flow/link-in-bio.ts b/client/landing/stepper/declarative-flow/link-in-bio.ts index 27906417af694..2dd7cafc1c0c1 100644 --- a/client/landing/stepper/declarative-flow/link-in-bio.ts +++ b/client/landing/stepper/declarative-flow/link-in-bio.ts @@ -22,6 +22,7 @@ import PlansStep from './internals/steps-repository/plans'; import Processing from './internals/steps-repository/processing-step'; import SiteCreationStep from './internals/steps-repository/site-creation-step'; import type { Flow, ProvidedDependencies } from './internals/types'; +import type { UserSelect } from '@automattic/data-stores'; const linkInBio: Flow = { name: LINK_IN_BIO_FLOW, @@ -46,7 +47,10 @@ const linkInBio: Flow = { const { setStepProgress } = useDispatch( ONBOARD_STORE ); const flowProgress = useFlowProgress( { stepName: _currentStepSlug, flowName } ); const siteSlug = useSiteSlug(); - const userIsLoggedIn = useSelect( ( select ) => select( USER_STORE ).isCurrentUserLoggedIn() ); + const userIsLoggedIn = useSelect( + ( select ) => ( select( USER_STORE ) as UserSelect ).isCurrentUserLoggedIn(), + [] + ); const locale = useLocale(); setStepProgress( flowProgress ); diff --git a/client/landing/stepper/declarative-flow/newsletter.ts b/client/landing/stepper/declarative-flow/newsletter.ts index bd0a03afaa679..57e8450f876ae 100644 --- a/client/landing/stepper/declarative-flow/newsletter.ts +++ b/client/landing/stepper/declarative-flow/newsletter.ts @@ -12,6 +12,7 @@ import NewsletterSetup from './internals/steps-repository/newsletter-setup'; import Subscribers from './internals/steps-repository/subscribers'; import { ProvidedDependencies } from './internals/types'; import type { Flow } from './internals/types'; +import type { UserSelect } from '@automattic/data-stores'; const newsletter: Flow = { name: NEWSLETTER_FLOW, @@ -29,7 +30,10 @@ const newsletter: Flow = { useStepNavigation( _currentStep, navigate ) { const flowName = this.name; - const userIsLoggedIn = useSelect( ( select ) => select( USER_STORE ).isCurrentUserLoggedIn() ); + const userIsLoggedIn = useSelect( + ( select ) => ( select( USER_STORE ) as UserSelect ).isCurrentUserLoggedIn(), + [] + ); const siteSlug = useSiteSlug(); const { setStepProgress } = useDispatch( ONBOARD_STORE ); const flowProgress = useFlowProgress( { diff --git a/client/landing/stepper/declarative-flow/plugin-bundle-flow.ts b/client/landing/stepper/declarative-flow/plugin-bundle-flow.ts index 2a25550fdc6ec..308ff7d46d522 100644 --- a/client/landing/stepper/declarative-flow/plugin-bundle-flow.ts +++ b/client/landing/stepper/declarative-flow/plugin-bundle-flow.ts @@ -23,6 +23,7 @@ import { } from './internals/types'; import pluginBundleData from './plugin-bundle-data'; import type { BundledPlugin } from './plugin-bundle-data'; +import type { OnboardSelect, SiteSelect, UserSelect } from '@automattic/data-stores'; const WRITE_INTENT_DEFAULT_THEME = 'livro'; const WRITE_INTENT_DEFAULT_THEME_STYLE_VARIATION = 'white'; @@ -33,8 +34,10 @@ const pluginBundleFlow: Flow = { useSteps() { const siteSlugParam = useSiteSlugParam(); - const pluginSlug = useSelect( ( select ) => - select( SITE_STORE ).getBundledPluginSlug( siteSlugParam || '' ) + const pluginSlug = useSelect( + ( select ) => + ( select( SITE_STORE ) as SiteSelect ).getBundledPluginSlug( siteSlugParam || '' ), + [ siteSlugParam ] ) as BundledPlugin; const steps = [ @@ -53,10 +56,22 @@ const pluginBundleFlow: Flow = { }, useStepNavigation( currentStep, navigate ) { const flowName = this.name; - const intent = useSelect( ( select ) => select( ONBOARD_STORE ).getIntent() ); - const goals = useSelect( ( select ) => select( ONBOARD_STORE ).getGoals() ); - const selectedDesign = useSelect( ( select ) => select( ONBOARD_STORE ).getSelectedDesign() ); - const startingPoint = useSelect( ( select ) => select( ONBOARD_STORE ).getStartingPoint() ); + const intent = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getIntent(), + [] + ); + const goals = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getGoals(), + [] + ); + const selectedDesign = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedDesign(), + [] + ); + const startingPoint = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getStartingPoint(), + [] + ); const siteSlugParam = useSiteSlugParam(); const site = useSite(); const currentUser = useSelector( getCurrentUser ); @@ -69,16 +84,25 @@ const pluginBundleFlow: Flow = { } const adminUrl = useSelect( - ( select ) => site && select( SITE_STORE ).getSiteOption( site.ID, 'admin_url' ) + ( select ) => + site && ( select( SITE_STORE ) as SiteSelect ).getSiteOption( site.ID, 'admin_url' ), + [ site ] ); const isAtomic = useSelect( - ( select ) => site && select( SITE_STORE ).isSiteAtomic( site.ID ) + ( select ) => site && ( select( SITE_STORE ) as SiteSelect ).isSiteAtomic( site.ID ), + [ site ] + ); + const storeType = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getStoreType(), + [] ); - const storeType = useSelect( ( select ) => select( ONBOARD_STORE ).getStoreType() ); const { setPendingAction, setStepProgress, resetOnboardStoreWithSkipFlags } = useDispatch( ONBOARD_STORE ); const { setIntentOnSite, setGoalsOnSite, setThemeOnSite } = useDispatch( SITE_STORE ); - const siteDetails = useSelect( ( select ) => site && select( SITE_STORE ).getSite( site.ID ) ); + const siteDetails = useSelect( + ( select ) => site && ( select( SITE_STORE ) as SiteSelect ).getSite( site.ID ), + [ site ] + ); const dispatch = reduxDispatch(); // Since we're mimicking a subset of the site-setup-flow, we're safe to use the siteSetupProgress. @@ -235,9 +259,13 @@ const pluginBundleFlow: Flow = { useAssertConditions(): AssertConditionResult { const siteSlug = useSiteSlugParam(); const siteId = useSiteIdParam(); - const userIsLoggedIn = useSelect( ( select ) => select( USER_STORE ).isCurrentUserLoggedIn() ); - const fetchingSiteError = useSelect( ( select ) => - select( SITE_STORE ).getFetchingSiteError() + const userIsLoggedIn = useSelect( + ( select ) => ( select( USER_STORE ) as UserSelect ).isCurrentUserLoggedIn(), + [] + ); + const fetchingSiteError = useSelect( + ( select ) => ( select( SITE_STORE ) as SiteSelect ).getFetchingSiteError(), + [] ); let result: AssertConditionResult = { state: AssertConditionState.SUCCESS }; diff --git a/client/landing/stepper/declarative-flow/sensei.ts b/client/landing/stepper/declarative-flow/sensei.ts index fe1fac03abd0b..a2e9056d042ce 100644 --- a/client/landing/stepper/declarative-flow/sensei.ts +++ b/client/landing/stepper/declarative-flow/sensei.ts @@ -11,6 +11,7 @@ import SenseiPlan from './internals/steps-repository/sensei-plan'; import SenseiPurpose from './internals/steps-repository/sensei-purpose'; import SenseiSetup from './internals/steps-repository/sensei-setup'; import { AssertConditionState, Flow } from './internals/types'; +import type { UserSelect } from '@automattic/data-stores'; import './internals/sensei.scss'; const sensei: Flow = { @@ -62,7 +63,10 @@ const sensei: Flow = { useAssertConditions() { const flowName = this.name; - const userIsLoggedIn = useSelect( ( select ) => select( USER_STORE ).isCurrentUserLoggedIn() ); + const userIsLoggedIn = useSelect( + ( select ) => ( select( USER_STORE ) as UserSelect ).isCurrentUserLoggedIn(), + [] + ); const locale = useLocale(); const logInUrl = locale && locale !== 'en' diff --git a/client/landing/stepper/declarative-flow/site-setup-flow.ts b/client/landing/stepper/declarative-flow/site-setup-flow.ts index ac5927ac2c05b..b737dc785e561 100644 --- a/client/landing/stepper/declarative-flow/site-setup-flow.ts +++ b/client/landing/stepper/declarative-flow/site-setup-flow.ts @@ -55,6 +55,7 @@ import { Flow, ProvidedDependencies, } from './internals/types'; +import type { OnboardSelect, SiteSelect, UserSelect } from '@automattic/data-stores'; const WRITE_INTENT_DEFAULT_THEME = 'livro'; const WRITE_INTENT_DEFAULT_THEME_STYLE_VARIATION = 'white'; @@ -69,7 +70,10 @@ const siteSetupFlow: Flow = { name: 'site-setup', useSideEffect( currentStep, navigate ) { - const selectedDesign = useSelect( ( select ) => select( ONBOARD_STORE ).getSelectedDesign() ); + const selectedDesign = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedDesign(), + [] + ); useEffect( () => { // Require to start the flow from the first step @@ -122,11 +126,23 @@ const siteSetupFlow: Flow = { }, useStepNavigation( currentStep, navigate ) { const flowName = this.name; - const intent = useSelect( ( select ) => select( ONBOARD_STORE ).getIntent() ); - const { getIntent } = useSelect( ( select ) => select( ONBOARD_STORE ) ); - const goals = useSelect( ( select ) => select( ONBOARD_STORE ).getGoals() ); - const selectedDesign = useSelect( ( select ) => select( ONBOARD_STORE ).getSelectedDesign() ); - const startingPoint = useSelect( ( select ) => select( ONBOARD_STORE ).getStartingPoint() ); + const intent = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getIntent(), + [] + ); + const { getIntent } = useSelect( ( select ) => select( ONBOARD_STORE ) as OnboardSelect, [] ); + const goals = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getGoals(), + [] + ); + const selectedDesign = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedDesign(), + [] + ); + const startingPoint = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getStartingPoint(), + [] + ); const siteSlugParam = useSiteSlugParam(); const site = useSite(); const currentUser = useSelector( getCurrentUser ); @@ -146,12 +162,18 @@ const siteSetupFlow: Flow = { } const adminUrl = useSelect( - ( select ) => site && select( SITE_STORE ).getSiteOption( site.ID, 'admin_url' ) + ( select ) => + site && ( select( SITE_STORE ) as SiteSelect ).getSiteOption( site.ID, 'admin_url' ), + [ site ] ); const isAtomic = useSelect( - ( select ) => site && select( SITE_STORE ).isSiteAtomic( site.ID ) + ( select ) => site && ( select( SITE_STORE ) as SiteSelect ).isSiteAtomic( site.ID ), + [ site ] + ); + const storeType = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getStoreType(), + [] ); - const storeType = useSelect( ( select ) => select( ONBOARD_STORE ).getStoreType() ); const { setPendingAction, setStepProgress, resetOnboardStoreWithSkipFlags, setIntent } = useDispatch( ONBOARD_STORE ); const { setIntentOnSite, setGoalsOnSite, setThemeOnSite, saveSiteSettings } = @@ -575,9 +597,13 @@ const siteSetupFlow: Flow = { useAssertConditions(): AssertConditionResult { const siteSlug = useSiteSlugParam(); const siteId = useSiteIdParam(); - const userIsLoggedIn = useSelect( ( select ) => select( USER_STORE ).isCurrentUserLoggedIn() ); - const fetchingSiteError = useSelect( ( select ) => - select( SITE_STORE ).getFetchingSiteError() + const userIsLoggedIn = useSelect( + ( select ) => ( select( USER_STORE ) as UserSelect ).isCurrentUserLoggedIn(), + [] + ); + const fetchingSiteError = useSelect( + ( select ) => ( select( SITE_STORE ) as SiteSelect ).getFetchingSiteError(), + [] ); let result: AssertConditionResult = { state: AssertConditionState.SUCCESS }; diff --git a/client/landing/stepper/declarative-flow/tailored-ecommerce-flow.ts b/client/landing/stepper/declarative-flow/tailored-ecommerce-flow.ts index d9839f3f62f10..de2427506cc37 100644 --- a/client/landing/stepper/declarative-flow/tailored-ecommerce-flow.ts +++ b/client/landing/stepper/declarative-flow/tailored-ecommerce-flow.ts @@ -23,13 +23,14 @@ import StoreProfiler from './internals/steps-repository/store-profiler'; import WaitForAtomic from './internals/steps-repository/wait-for-atomic'; import { AssertConditionState } from './internals/types'; import type { Flow, ProvidedDependencies, AssertConditionResult } from './internals/types'; -import type { SiteDetailsPlan } from '@automattic/data-stores'; +import type { OnboardSelect, SiteDetailsPlan, UserSelect } from '@automattic/data-stores'; const ecommerceFlow: Flow = { name: ECOMMERCE_FLOW, useSteps() { - const recurType = useSelect( ( select ) => - select( ONBOARD_STORE ).getEcommerceFlowRecurType() + const recurType = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getEcommerceFlowRecurType(), + [] ); useEffect( () => { @@ -49,16 +50,22 @@ const ecommerceFlow: Flow = { }, useAssertConditions(): AssertConditionResult { - const userIsLoggedIn = useSelect( ( select ) => select( USER_STORE ).isCurrentUserLoggedIn() ); + const userIsLoggedIn = useSelect( + ( select ) => ( select( USER_STORE ) as UserSelect ).isCurrentUserLoggedIn(), + [] + ); let result: AssertConditionResult = { state: AssertConditionState.SUCCESS }; const flags = new URLSearchParams( window.location.search ).get( 'flags' ); const flowName = this.name; const locale = useLocale(); - const { recurType } = useSelect( ( select ) => ( { - recurType: select( ONBOARD_STORE ).getEcommerceFlowRecurType(), - } ) ); + const { recurType } = useSelect( + ( select ) => ( { + recurType: ( select( ONBOARD_STORE ) as OnboardSelect ).getEcommerceFlowRecurType(), + } ), + [] + ); const getStartUrl = () => { let hasFlowParams = false; @@ -101,10 +108,13 @@ const ecommerceFlow: Flow = { const { setStepProgress, setPlanCartItem } = useDispatch( ONBOARD_STORE ); const flowProgress = useFlowProgress( { stepName: _currentStepName, flowName } ); setStepProgress( flowProgress ); - const { selectedDesign, recurType } = useSelect( ( select ) => ( { - selectedDesign: select( ONBOARD_STORE ).getSelectedDesign(), - recurType: select( ONBOARD_STORE ).getEcommerceFlowRecurType(), - } ) ); + const { selectedDesign, recurType } = useSelect( + ( select ) => ( { + selectedDesign: ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedDesign(), + recurType: ( select( ONBOARD_STORE ) as OnboardSelect ).getEcommerceFlowRecurType(), + } ), + [] + ); const selectedPlan = recurType === ecommerceFlowRecurTypes.YEARLY ? PLAN_ECOMMERCE : PLAN_ECOMMERCE_MONTHLY; diff --git a/client/landing/stepper/declarative-flow/trial-wooexpress-flow.ts b/client/landing/stepper/declarative-flow/trial-wooexpress-flow.ts index c85b7a84a0b60..b742cd4f3ed42 100644 --- a/client/landing/stepper/declarative-flow/trial-wooexpress-flow.ts +++ b/client/landing/stepper/declarative-flow/trial-wooexpress-flow.ts @@ -14,6 +14,7 @@ import WaitForAtomic from './internals/steps-repository/wait-for-atomic'; import WaitForPluginInstall from './internals/steps-repository/wait-for-plugin-install'; import { AssertConditionState } from './internals/types'; import type { AssertConditionResult, Flow, ProvidedDependencies } from './internals/types'; +import type { OnboardSelect, SiteSelect, UserSelect } from '@automattic/data-stores'; const wooexpress: Flow = { name: 'wooexpress', @@ -29,7 +30,10 @@ const wooexpress: Flow = { ]; }, useAssertConditions(): AssertConditionResult { - const userIsLoggedIn = useSelect( ( select ) => select( USER_STORE ).isCurrentUserLoggedIn() ); + const userIsLoggedIn = useSelect( + ( select ) => ( select( USER_STORE ) as UserSelect ).isCurrentUserLoggedIn(), + [] + ); let result: AssertConditionResult = { state: AssertConditionState.SUCCESS }; const flowName = this.name; @@ -73,7 +77,10 @@ const wooexpress: Flow = { }, useStepNavigation( currentStep, navigate ) { const flowName = this.name; - const intent = useSelect( ( select ) => select( ONBOARD_STORE ).getIntent() ); + const intent = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getIntent(), + [] + ); const siteSlugParam = useSiteSlugParam(); const { setStepProgress, setPluginsToVerify } = useDispatch( ONBOARD_STORE ); @@ -82,7 +89,7 @@ const wooexpress: Flow = { const flowProgress = useSiteSetupFlowProgress( currentStep, intent ); setStepProgress( flowProgress ); - const { getSiteIdBySlug } = useSelect( ( select ) => select( SITE_STORE ) ); + const { getSiteIdBySlug } = useSelect( ( select ) => select( SITE_STORE ) as SiteSelect, [] ); const exitFlow = ( to: string ) => { window.location.assign( to ); diff --git a/client/landing/stepper/declarative-flow/videopress.ts b/client/landing/stepper/declarative-flow/videopress.ts index 285b499fce107..65a282a4e287f 100644 --- a/client/landing/stepper/declarative-flow/videopress.ts +++ b/client/landing/stepper/declarative-flow/videopress.ts @@ -13,6 +13,7 @@ import ProcessingStep from './internals/steps-repository/processing-step'; import SiteOptions from './internals/steps-repository/site-options'; import VideomakerSetup from './internals/steps-repository/videomaker-setup'; import type { Flow, ProvidedDependencies } from './internals/types'; +import type { OnboardSelect, UserSelect } from '@automattic/data-stores'; const videopress: Flow = { name: VIDEOPRESS_FLOW, @@ -56,8 +57,14 @@ const videopress: Flow = { const flowProgress = useFlowProgress( { stepName: _currentStep, flowName: name } ); setStepProgress( flowProgress ); const _siteSlug = useSiteSlug(); - const userIsLoggedIn = useSelect( ( select ) => select( USER_STORE ).isCurrentUserLoggedIn() ); - const _siteTitle = useSelect( ( select ) => select( ONBOARD_STORE ).getSelectedSiteTitle() ); + const userIsLoggedIn = useSelect( + ( select ) => ( select( USER_STORE ) as UserSelect ).isCurrentUserLoggedIn(), + [] + ); + const _siteTitle = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getSelectedSiteTitle(), + [] + ); const locale = useLocale(); const clearOnboardingSiteOptions = () => { diff --git a/client/landing/stepper/declarative-flow/with-theme-assembler-flow.ts b/client/landing/stepper/declarative-flow/with-theme-assembler-flow.ts index 0cc75fe780779..1313838e1521f 100644 --- a/client/landing/stepper/declarative-flow/with-theme-assembler-flow.ts +++ b/client/landing/stepper/declarative-flow/with-theme-assembler-flow.ts @@ -10,6 +10,7 @@ import { recordSubmitStep } from './internals/analytics/record-submit-step'; import PatternAssembler from './internals/steps-repository/pattern-assembler/lazy'; import Processing from './internals/steps-repository/processing-step'; import { Flow, ProvidedDependencies } from './internals/types'; +import type { OnboardSelect } from '@automattic/data-stores'; import type { Design } from '@automattic/design-picker/src/types'; const SiteIntent = Onboard.SiteIntent; @@ -39,7 +40,10 @@ const withThemeAssemblerFlow: Flow = { useStepNavigation( _currentStep, navigate ) { const flowName = this.name; - const intent = useSelect( ( select ) => select( ONBOARD_STORE ).getIntent() ); + const intent = useSelect( + ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getIntent(), + [] + ); const { setStepProgress, setPendingAction } = useDispatch( ONBOARD_STORE ); const flowProgress = useFlowProgress( { stepName: _currentStep, flowName } ); setStepProgress( flowProgress ); diff --git a/client/landing/stepper/declarative-flow/write.ts b/client/landing/stepper/declarative-flow/write.ts index 09e864e907b0a..1910505146eca 100644 --- a/client/landing/stepper/declarative-flow/write.ts +++ b/client/landing/stepper/declarative-flow/write.ts @@ -15,6 +15,7 @@ import { Flow, ProvidedDependencies, } from './internals/types'; +import type { UserSelect } from '@automattic/data-stores'; const write: Flow = { name: WRITE_FLOW, @@ -82,7 +83,10 @@ const write: Flow = { }, useAssertConditions(): AssertConditionResult { - const userIsLoggedIn = useSelect( ( select ) => select( USER_STORE ).isCurrentUserLoggedIn() ); + const userIsLoggedIn = useSelect( + ( select ) => ( select( USER_STORE ) as UserSelect ).isCurrentUserLoggedIn(), + [] + ); let result: AssertConditionResult = { state: AssertConditionState.SUCCESS }; const queryParams = new URLSearchParams( window.location.search ); diff --git a/client/landing/stepper/hooks/use-detect-matching-anchor-site.ts b/client/landing/stepper/hooks/use-detect-matching-anchor-site.ts index a81db69d0145d..6126f2c998239 100644 --- a/client/landing/stepper/hooks/use-detect-matching-anchor-site.ts +++ b/client/landing/stepper/hooks/use-detect-matching-anchor-site.ts @@ -4,6 +4,7 @@ import wpcom from 'calypso/lib/wp'; import { USER_STORE } from '../stores'; import { useAnchorFmParams } from './use-anchor-fm-params'; import { useIsAnchorFm } from './use-is-anchor-fm'; +import type { UserSelect } from '@automattic/data-stores'; interface AnchorEndpointResult { location: string | false; @@ -23,7 +24,10 @@ export default function useDetectMatchingAnchorSite(): boolean { anchorFmIsNewSite, } = useAnchorFmParams(); const isAnchorFm = useIsAnchorFm(); - const currentUserExists = useSelect( ( select ) => !! select( USER_STORE ).getCurrentUser() ); + const currentUserExists = useSelect( + ( select ) => !! ( select( USER_STORE ) as UserSelect ).getCurrentUser(), + [] + ); const [ isLoading, setIsLoading ] = useState( !! ( isAnchorFm && currentUserExists ) ); useEffect( () => { diff --git a/client/landing/stepper/hooks/use-intent.ts b/client/landing/stepper/hooks/use-intent.ts index 5076b1d811617..1e633085fb35b 100644 --- a/client/landing/stepper/hooks/use-intent.ts +++ b/client/landing/stepper/hooks/use-intent.ts @@ -1,6 +1,7 @@ import { useSelect } from '@wordpress/data'; import { ONBOARD_STORE } from '../stores'; +import type { OnboardSelect } from '@automattic/data-stores'; export function useIntent() { - return useSelect( ( select ) => select( ONBOARD_STORE ).getIntent() ); + return useSelect( ( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getIntent(), [] ); } diff --git a/client/landing/stepper/hooks/use-is-plugin-bundle-eligible.ts b/client/landing/stepper/hooks/use-is-plugin-bundle-eligible.ts index e7341ddad129e..eb80417f34280 100644 --- a/client/landing/stepper/hooks/use-is-plugin-bundle-eligible.ts +++ b/client/landing/stepper/hooks/use-is-plugin-bundle-eligible.ts @@ -2,14 +2,18 @@ import { FEATURE_WOOP, WPCOM_FEATURES_ATOMIC } from '@automattic/calypso-product import { useSelect } from '@wordpress/data'; import { SITE_STORE } from '../stores'; import { useSite } from './use-site'; +import type { SiteSelect } from '@automattic/data-stores'; export function useIsPluginBundleEligible(): boolean | null { const site = useSite(); - const hasWooFeature = useSelect( ( select ) => - select( SITE_STORE ).siteHasFeature( site?.ID, FEATURE_WOOP ) + const hasWooFeature = useSelect( + ( select ) => ( select( SITE_STORE ) as SiteSelect ).siteHasFeature( site?.ID, FEATURE_WOOP ), + [ site ] ); - const hasAtomicFeature = useSelect( ( select ) => - select( SITE_STORE ).siteHasFeature( site?.ID, WPCOM_FEATURES_ATOMIC ) + const hasAtomicFeature = useSelect( + ( select ) => + ( select( SITE_STORE ) as SiteSelect ).siteHasFeature( site?.ID, WPCOM_FEATURES_ATOMIC ), + [ site ] ); return hasWooFeature && hasAtomicFeature; diff --git a/client/landing/stepper/hooks/use-is-site-atomic.ts b/client/landing/stepper/hooks/use-is-site-atomic.ts index 4cf8c30f8e0d7..bb0b0c17bf931 100644 --- a/client/landing/stepper/hooks/use-is-site-atomic.ts +++ b/client/landing/stepper/hooks/use-is-site-atomic.ts @@ -1,6 +1,10 @@ import { useSelect } from '@wordpress/data'; import { SITE_STORE } from '../stores'; +import type { SiteSelect } from '@automattic/data-stores'; export function useIsSiteAtomic( siteId: number | string ): boolean | null { - return useSelect( ( select ) => select( SITE_STORE ).isSiteAtomic( siteId ) ); + return useSelect( + ( select ) => ( select( SITE_STORE ) as SiteSelect ).isSiteAtomic( siteId ), + [ siteId ] + ); } diff --git a/client/landing/stepper/hooks/use-record-signup-complete.ts b/client/landing/stepper/hooks/use-record-signup-complete.ts index 4f07a16d1f7a1..a2967895c7f3f 100644 --- a/client/landing/stepper/hooks/use-record-signup-complete.ts +++ b/client/landing/stepper/hooks/use-record-signup-complete.ts @@ -3,12 +3,16 @@ import { useCallback } from 'react'; import { USER_STORE } from 'calypso/landing/stepper/stores'; import { recordSignupComplete } from 'calypso/lib/analytics/signup'; import { useSite } from './use-site'; +import type { UserSelect } from '@automattic/data-stores'; export const useRecordSignupComplete = ( flow: string | null ) => { const site = useSite(); const siteId = site?.ID || null; const theme = site?.options?.theme_slug || ''; - const siteCount = useSelect( ( select ) => select( USER_STORE ).getCurrentUser() )?.site_count; + const siteCount = useSelect( + ( select ) => ( select( USER_STORE ) as UserSelect ).getCurrentUser(), + [] + )?.site_count; return useCallback( () => { recordSignupComplete( diff --git a/client/landing/stepper/hooks/use-site-copy.tsx b/client/landing/stepper/hooks/use-site-copy.tsx index ad93338f00889..8c2a2dbe1cf7e 100644 --- a/client/landing/stepper/hooks/use-site-copy.tsx +++ b/client/landing/stepper/hooks/use-site-copy.tsx @@ -16,6 +16,7 @@ import { import getSiteFeatures from 'calypso/state/selectors/get-site-features'; import siteHasFeature from 'calypso/state/selectors/site-has-feature'; import { fetchSiteFeatures } from 'calypso/state/sites/features/actions'; +import type { SiteSelect } from '@automattic/data-stores'; import type { SiteExcerptData } from 'calypso/data/sites/site-excerpt-types'; import type { Purchase } from 'calypso/lib/purchases/types'; @@ -69,8 +70,9 @@ export const useSiteCopy = ( return siteFeatures ? siteFeatures : { isRequesting: true }; } ); const isAtomic = useSelect( - ( select ) => site && options.enabled && select( SITE_STORE ).isSiteAtomic( site?.ID ), - [ site?.ID, options.enabled ] + ( select ) => + site && options.enabled && ( select( SITE_STORE ) as SiteSelect ).isSiteAtomic( site?.ID ), + [ site, options.enabled ] ); const plan = site?.plan; const isSiteOwner = site?.site_owner === userId; diff --git a/client/landing/stepper/hooks/use-site-domains.ts b/client/landing/stepper/hooks/use-site-domains.ts index 629e7c184c7e5..9e0d8b5162b18 100644 --- a/client/landing/stepper/hooks/use-site-domains.ts +++ b/client/landing/stepper/hooks/use-site-domains.ts @@ -1,14 +1,17 @@ import { useSelect } from '@wordpress/data'; import { SITE_STORE } from '../stores'; import { useQuery } from './use-query'; +import type { SiteSelect } from '@automattic/data-stores'; export function useSiteDomains() { const siteSlug = useQuery().get( 'siteSlug' ); const siteId = useSelect( - ( select ) => siteSlug && select( SITE_STORE ).getSiteIdBySlug( siteSlug ) + ( select ) => siteSlug && ( select( SITE_STORE ) as SiteSelect ).getSiteIdBySlug( siteSlug ), + [ siteSlug ] ); const siteDomains = useSelect( - ( select ) => siteId && select( SITE_STORE ).getSiteDomains( siteId ) + ( select ) => siteId && ( select( SITE_STORE ) as SiteSelect ).getSiteDomains( siteId ), + [ siteId ] ); if ( siteSlug && siteId && siteDomains ) { diff --git a/client/landing/stepper/hooks/use-site-setup-error.ts b/client/landing/stepper/hooks/use-site-setup-error.ts index dc6e03f2cf721..bc4233e6a6bea 100644 --- a/client/landing/stepper/hooks/use-site-setup-error.ts +++ b/client/landing/stepper/hooks/use-site-setup-error.ts @@ -1,6 +1,7 @@ import { useSelect } from '@wordpress/data'; import { SITE_STORE } from '../stores'; +import type { SiteSelect } from '@automattic/data-stores'; export function useSiteSetupError() { - return useSelect( ( select ) => select( SITE_STORE ).getSiteSetupError() ); + return useSelect( ( select ) => ( select( SITE_STORE ) as SiteSelect ).getSiteSetupError(), [] ); } diff --git a/client/landing/stepper/hooks/use-site.ts b/client/landing/stepper/hooks/use-site.ts index 0461fb0ac90c7..488fcb7e4971c 100644 --- a/client/landing/stepper/hooks/use-site.ts +++ b/client/landing/stepper/hooks/use-site.ts @@ -2,17 +2,22 @@ import { useSelect } from '@wordpress/data'; import { SITE_STORE } from '../stores'; import { useSiteIdParam } from './use-site-id-param'; import { useSiteSlugParam } from './use-site-slug-param'; +import type { SiteSelect } from '@automattic/data-stores'; export function useSite() { const siteSlug = useSiteSlugParam(); const siteIdParam = useSiteIdParam(); const siteId = useSelect( - ( select ) => siteSlug && select( SITE_STORE ).getSiteIdBySlug( siteSlug ) + ( select ) => siteSlug && ( select( SITE_STORE ) as SiteSelect ).getSiteIdBySlug( siteSlug ), + [ siteSlug ] ); const site = useSelect( ( select ) => ( siteId || siteIdParam ) && - select( SITE_STORE ).getSite( ( siteId ?? siteIdParam ) as string | number ) + ( select( SITE_STORE ) as SiteSelect ).getSite( + ( siteId ?? siteIdParam ) as string | number + ), + [ siteId, siteIdParam ] ); if ( ( siteSlug || siteIdParam ) && site ) { diff --git a/client/landing/stepper/hooks/use-user-can-manage-options.ts b/client/landing/stepper/hooks/use-user-can-manage-options.ts index 52245b9a0693b..e2b762c6f2086 100644 --- a/client/landing/stepper/hooks/use-user-can-manage-options.ts +++ b/client/landing/stepper/hooks/use-user-can-manage-options.ts @@ -4,12 +4,13 @@ import { canCurrentUser } from 'calypso/state/selectors/can-current-user'; import isRequestingSites from 'calypso/state/sites/selectors/is-requesting-sites'; import { SITE_STORE } from '../stores'; import { useSiteSlugParam } from './use-site-slug-param'; +import type { SiteSelect } from '@automattic/data-stores'; export function useCanUserManageOptions() { const siteSlug = useSiteSlugParam(); const siteId = useSelect( - ( select ) => siteSlug && select( SITE_STORE ).getSiteIdBySlug( siteSlug ), - undefined + ( select ) => siteSlug && ( select( SITE_STORE ) as SiteSelect ).getSiteIdBySlug( siteSlug ), + [ siteSlug ] ); const isRequesting = useSelector( ( state ) => isRequestingSites( state ) ); const hasManageOptionsCap = useSelector( ( state ) => diff --git a/client/layout/masterbar/checkout.tsx b/client/layout/masterbar/checkout.tsx index 101d3ea7fb1f6..897f689b31058 100644 --- a/client/layout/masterbar/checkout.tsx +++ b/client/layout/masterbar/checkout.tsx @@ -18,6 +18,7 @@ import { leaveCheckout } from 'calypso/my-sites/checkout/composite-checkout/lib/ import useCartKey from 'calypso/my-sites/checkout/use-cart-key'; import Item from './item'; import Masterbar from './masterbar'; +import type { HelpCenterSelect } from '@automattic/data-stores'; const HELP_CENTER_STORE = HelpCenter.register(); @@ -48,8 +49,9 @@ const CheckoutMasterbar = ( { const [ isModalVisible, setIsModalVisible ] = useState( false ); const { setShowHelpCenter } = useDataStoreDispatch( HELP_CENTER_STORE ); - const isShowingHelpCenter = useDataStoreSelect( ( select ) => - select( HELP_CENTER_STORE ).isHelpCenterShown() + const isShowingHelpCenter = useDataStoreSelect( + ( select ) => ( select( HELP_CENTER_STORE ) as HelpCenterSelect ).isHelpCenterShown(), + [] ); const closeAndLeave = () => diff --git a/client/my-sites/checkout/composite-checkout/components/checkout-main.tsx b/client/my-sites/checkout/composite-checkout/components/checkout-main.tsx index 2ce3d33de2a7c..7b40cfd9c6833 100644 --- a/client/my-sites/checkout/composite-checkout/components/checkout-main.tsx +++ b/client/my-sites/checkout/composite-checkout/components/checkout-main.tsx @@ -57,11 +57,14 @@ import weChatProcessor from '../lib/we-chat-processor'; import webPayProcessor from '../lib/web-pay-processor'; import { StoredCard } from '../types/stored-cards'; import WPCheckout from './wp-checkout'; +import type { WpcomCheckoutStoreSelectors as _WpcomCheckoutStoreSelectors } from '../hooks/wpcom-store'; import type { PaymentProcessorOptions } from '../types/payment-processors'; import type { CheckoutPageErrorCallback } from '@automattic/composite-checkout'; import type { MinimalRequestCartProduct } from '@automattic/shopping-cart'; import type { CountryListItem, CheckoutPaymentMethodSlug } from '@automattic/wpcom-checkout'; +type WpcomCheckoutStoreSelectors = _WpcomCheckoutStoreSelectors | undefined; + const { colors } = colorStudio; const debug = debugFactory( 'calypso:composite-checkout:composite-checkout' ); @@ -336,9 +339,14 @@ export default function CheckoutMain( { // Only wait for stored cards to load if we are using cards ( allowedPaymentMethods.includes( 'card' ) && isLoadingStoredCards ); - const contactDetails = useSelect( ( select ) => select( 'wpcom-checkout' )?.getContactInfo() ); - const recaptchaClientId = useSelect( ( select ) => - select( 'wpcom-checkout' )?.getRecaptchaClientId() + const contactDetails = useSelect( + ( select ) => ( select( 'wpcom-checkout' ) as WpcomCheckoutStoreSelectors )?.getContactInfo(), + [] + ); + const recaptchaClientId = useSelect( + ( select ) => + ( select( 'wpcom-checkout' ) as WpcomCheckoutStoreSelectors )?.getRecaptchaClientId(), + [] ); const paymentMethods = arePaymentMethodsLoading diff --git a/client/my-sites/checkout/composite-checkout/components/contact-details-container.tsx b/client/my-sites/checkout/composite-checkout/components/contact-details-container.tsx index b8673ca2cd610..4ed2cff95aa3c 100644 --- a/client/my-sites/checkout/composite-checkout/components/contact-details-container.tsx +++ b/client/my-sites/checkout/composite-checkout/components/contact-details-container.tsx @@ -17,6 +17,7 @@ import { } from '../types/wpcom-store-state'; import DomainContactDetails from './domain-contact-details'; import TaxFields from './tax-fields'; +import type { WpcomCheckoutStoreSelectors } from '../hooks/wpcom-store'; import type { DomainContactDetails as DomainContactDetailsData } from '@automattic/shopping-cart'; import type { CountryListItem, @@ -53,7 +54,12 @@ export default function ContactDetailsContainer( { .filter( ( product ) => ! isDomainMapping( product ) ) .map( getDomain ); const checkoutActions = useDispatch( 'wpcom-checkout' ); - const { email } = useSelect( ( select ) => select( 'wpcom-checkout' )?.getContactInfo() ?? {} ); + const { email } = useSelect( + ( select ) => + ( select( 'wpcom-checkout' ) as WpcomCheckoutStoreSelectors | undefined )?.getContactInfo() ?? + {}, + [] + ); if ( ! checkoutActions ) { return null; diff --git a/client/my-sites/checkout/composite-checkout/components/international-fee-notice.tsx b/client/my-sites/checkout/composite-checkout/components/international-fee-notice.tsx index 15639926c9136..8846a467f3dde 100644 --- a/client/my-sites/checkout/composite-checkout/components/international-fee-notice.tsx +++ b/client/my-sites/checkout/composite-checkout/components/international-fee-notice.tsx @@ -1,9 +1,14 @@ import { useSelect } from '@wordpress/data'; import { translate } from 'i18n-calypso'; import CheckoutTermsItem from 'calypso/my-sites/checkout/composite-checkout/components/checkout-terms-item'; +import type { WpcomCheckoutStoreSelectors } from '../hooks/wpcom-store'; export const InternationalFeeNotice = () => { - const contactInfo = useSelect( ( select ) => select( 'wpcom-checkout' )?.getContactInfo() ); + const contactInfo = useSelect( + ( select ) => + ( select( 'wpcom-checkout' ) as WpcomCheckoutStoreSelectors | undefined )?.getContactInfo(), + [] + ); if ( contactInfo?.countryCode?.value !== 'US' ) { const internationalFeeAgreement = translate( diff --git a/client/my-sites/checkout/composite-checkout/components/vat-form/index.tsx b/client/my-sites/checkout/composite-checkout/components/vat-form/index.tsx index 08979e60d8ac3..6c9b1c72d484d 100644 --- a/client/my-sites/checkout/composite-checkout/components/vat-form/index.tsx +++ b/client/my-sites/checkout/composite-checkout/components/vat-form/index.tsx @@ -8,6 +8,7 @@ import FormSettingExplanation from 'calypso/components/forms/form-setting-explan import { CALYPSO_CONTACT } from 'calypso/lib/url/support'; import useVatDetails from 'calypso/me/purchases/vat-info/use-vat-details'; import { recordTracksEvent } from 'calypso/state/analytics/actions'; +import type { WpcomCheckoutStoreSelectors } from '../../hooks/wpcom-store'; import './style.css'; @@ -64,7 +65,10 @@ export function VatForm( { } ) { const translate = useTranslate(); const vatDetailsInForm = useSelect( - ( select ) => select( 'wpcom-checkout' )?.getVatDetails() ?? {} + ( select ) => + ( select( 'wpcom-checkout' ) as WpcomCheckoutStoreSelectors | undefined )?.getVatDetails() ?? + {}, + [] ); const wpcomStoreActions = useDispatch( 'wpcom-checkout' ); const setVatDetailsInForm = wpcomStoreActions?.setVatDetails; diff --git a/client/my-sites/checkout/composite-checkout/components/wp-checkout.tsx b/client/my-sites/checkout/composite-checkout/components/wp-checkout.tsx index 7971a7d03011e..18afdc32844ab 100644 --- a/client/my-sites/checkout/composite-checkout/components/wp-checkout.tsx +++ b/client/my-sites/checkout/composite-checkout/components/wp-checkout.tsx @@ -66,10 +66,13 @@ import WPCheckoutOrderSummary from './wp-checkout-order-summary'; import WPContactForm from './wp-contact-form'; import WPContactFormSummary from './wp-contact-form-summary'; import type { OnChangeItemVariant } from './item-variation-picker'; +import type { WpcomCheckoutStoreSelectors as _WpcomCheckoutStoreSelectors } from '../hooks/wpcom-store'; import type { CheckoutPageErrorCallback } from '@automattic/composite-checkout'; import type { RemoveProductFromCart, MinimalRequestCartProduct } from '@automattic/shopping-cart'; import type { CountryListItem } from '@automattic/wpcom-checkout'; +type WpcomCheckoutStoreSelectors = _WpcomCheckoutStoreSelectors | undefined; + const debug = debugFactory( 'calypso:composite-checkout:wp-checkout' ); // This will make converting to TS less noisy. The order of components can be reorganized later @@ -185,9 +188,15 @@ export default function WPCheckout( { const contactDetailsType = getContactDetailsType( responseCart ); - const contactInfo = useSelect( ( sel ) => sel( 'wpcom-checkout' )?.getContactInfo() ?? {} ); + const contactInfo = useSelect( + ( sel ) => ( sel( 'wpcom-checkout' ) as WpcomCheckoutStoreSelectors )?.getContactInfo() ?? {}, + [] + ); - const vatDetailsInForm = useSelect( ( sel ) => sel( 'wpcom-checkout' )?.getVatDetails() ?? {} ); + const vatDetailsInForm = useSelect( + ( sel ) => ( sel( 'wpcom-checkout' ) as WpcomCheckoutStoreSelectors )?.getVatDetails() ?? {}, + [] + ); const { setVatDetails, vatDetails: vatDetailsFromServer } = useVatDetails(); const checkoutActions = useDispatch( 'wpcom-checkout' ); diff --git a/client/my-sites/checkout/composite-checkout/components/wp-contact-form-summary.tsx b/client/my-sites/checkout/composite-checkout/components/wp-contact-form-summary.tsx index eee79d02efe21..f160ec8b581d2 100644 --- a/client/my-sites/checkout/composite-checkout/components/wp-contact-form-summary.tsx +++ b/client/my-sites/checkout/composite-checkout/components/wp-contact-form-summary.tsx @@ -4,6 +4,7 @@ import { useSelect } from '@wordpress/data'; import { hasOnlyRenewalItems } from 'calypso/lib/cart-values/cart-items'; import useCartKey from 'calypso/my-sites/checkout/use-cart-key'; import { SummaryLine, SummaryDetails } from './summary-details'; +import type { WpcomCheckoutStoreSelectors } from '../hooks/wpcom-store'; import type { ResponseCart } from '@automattic/shopping-cart'; import type { ManagedContactDetails } from '@automattic/wpcom-checkout'; @@ -26,7 +27,12 @@ export default function WPContactFormSummary( { isGSuiteInCart: boolean; isLoggedOutCart: boolean; } ) { - const contactInfo = useSelect( ( select ) => select( 'wpcom-checkout' )?.getContactInfo() ?? {} ); + const contactInfo = useSelect( + ( select ) => + ( select( 'wpcom-checkout' ) as WpcomCheckoutStoreSelectors | undefined )?.getContactInfo() ?? + {}, + [] + ); const cartKey = useCartKey(); const { responseCart } = useShoppingCart( cartKey ); const isRenewal = hasOnlyRenewalItems( responseCart ); diff --git a/client/my-sites/checkout/composite-checkout/components/wp-contact-form.tsx b/client/my-sites/checkout/composite-checkout/components/wp-contact-form.tsx index fc5ad43a07165..f34a2df9da901 100644 --- a/client/my-sites/checkout/composite-checkout/components/wp-contact-form.tsx +++ b/client/my-sites/checkout/composite-checkout/components/wp-contact-form.tsx @@ -3,6 +3,7 @@ import styled from '@emotion/styled'; import { useSelect } from '@wordpress/data'; import useCachedDomainContactDetails from '../hooks/use-cached-domain-contact-details'; import ContactDetailsContainer from './contact-details-container'; +import type { WpcomCheckoutStoreSelectors } from '../hooks/wpcom-store'; import type { CountryListItem, ContactDetailsType } from '@automattic/wpcom-checkout'; const BillingFormFields = styled.div` @@ -34,7 +35,12 @@ export default function WPContactForm( { isLoggedOutCart: boolean; setShouldShowContactDetailsValidationErrors: ( allowed: boolean ) => void; } ) { - const contactInfo = useSelect( ( select ) => select( 'wpcom-checkout' )?.getContactInfo() ?? {} ); + const contactInfo = useSelect( + ( select ) => + ( select( 'wpcom-checkout' ) as WpcomCheckoutStoreSelectors | undefined )?.getContactInfo() ?? + {}, + [] + ); const { formStatus } = useFormStatus(); const isStepActive = useIsStepActive(); const isDisabled = ! isStepActive || formStatus !== FormStatus.READY; diff --git a/client/my-sites/checkout/composite-checkout/hooks/use-cached-domain-contact-details.ts b/client/my-sites/checkout/composite-checkout/hooks/use-cached-domain-contact-details.ts index 19efeb61d21f0..2362f1dbdf186 100644 --- a/client/my-sites/checkout/composite-checkout/hooks/use-cached-domain-contact-details.ts +++ b/client/my-sites/checkout/composite-checkout/hooks/use-cached-domain-contact-details.ts @@ -17,6 +17,12 @@ import type { const debug = debugFactory( 'calypso:composite-checkout:use-cached-domain-contact-details' ); +type CheckoutStoreMappedActions = { + loadDomainContactDetailsFromCache?: ( + payload: PossiblyCompleteDomainContactDetails + ) => Promise< PossiblyCompleteDomainContactDetails >; +}; + function useCachedContactDetails(): PossiblyCompleteDomainContactDetails | null { const reduxDispatch = useReduxDispatch(); const haveRequestedCachedDetails = useRef< 'not-started' | 'pending' | 'done' >( 'not-started' ); @@ -51,7 +57,8 @@ function useCachedContactDetailsForCheckoutForm( ? getCountryPostalCodeSupport( countriesList, cachedContactDetails.countryCode ) : false; - const checkoutStoreActions = useDispatch( 'wpcom-checkout' ); + const checkoutStoreActions: CheckoutStoreMappedActions | undefined = + useDispatch( 'wpcom-checkout' ); if ( ! checkoutStoreActions?.loadDomainContactDetailsFromCache ) { throw new Error( 'useCachedContactDetailsForCheckoutForm must be run after the checkout data store has been initialized' @@ -110,7 +117,7 @@ function useCachedContactDetailsForCheckoutForm( setShouldShowContactDetailsValidationErrors( true ); setComplete( true ); } ) - .catch( ( error ) => { + .catch( ( error: Error ) => { setShouldShowContactDetailsValidationErrors( true ); isMounted.current && setComplete( true ); // eslint-disable-next-line no-console diff --git a/client/my-sites/checkout/composite-checkout/hooks/wpcom-store.ts b/client/my-sites/checkout/composite-checkout/hooks/wpcom-store.ts index 41473dd75882c..603ae9d499931 100644 --- a/client/my-sites/checkout/composite-checkout/hooks/wpcom-store.ts +++ b/client/my-sites/checkout/composite-checkout/hooks/wpcom-store.ts @@ -1,4 +1,4 @@ -import { registerStore } from '@wordpress/data'; +import { register, registerStore } from '@wordpress/data'; import { useRef } from 'react'; import { emptyManagedContactDetails, @@ -40,18 +40,13 @@ type WpcomStoreAction = export const STORE_KEY = 'wpcom-checkout'; -export interface WpcomCheckoutStore extends ReturnType< typeof registerStore > { +export interface WpcomCheckoutStore extends ReturnType< typeof register > { getState: () => WpcomStoreState; } export type WpcomCheckoutStoreSelectors = SelectFromMap< typeof selectors >; export type WpcomCheckoutStoreActions = DispatchFromMap< typeof actions >; -declare module '@wordpress/data' { - function select( key: typeof STORE_KEY ): WpcomCheckoutStoreSelectors | undefined; - function dispatch( key: typeof STORE_KEY ): WpcomCheckoutStoreActions | undefined; -} - const actions = { applyDomainContactValidationResults( payload: ManagedContactDetailsErrors ): WpcomStoreAction { return { type: 'APPLY_DOMAIN_CONTACT_VALIDATION_RESULTS', payload }; diff --git a/client/my-sites/checkout/composite-checkout/payment-methods/credit-card/contact-fields.tsx b/client/my-sites/checkout/composite-checkout/payment-methods/credit-card/contact-fields.tsx index 07f35f83b9d58..04c7242df5356 100644 --- a/client/my-sites/checkout/composite-checkout/payment-methods/credit-card/contact-fields.tsx +++ b/client/my-sites/checkout/composite-checkout/payment-methods/credit-card/contact-fields.tsx @@ -3,6 +3,8 @@ import { useSelect } from '@wordpress/data'; import TaxFields from 'calypso/my-sites/checkout/composite-checkout/components/tax-fields'; import useCountryList from 'calypso/my-sites/checkout/composite-checkout/hooks/use-country-list'; import { CountrySpecificPaymentFields } from '../../components/country-specific-payment-fields'; +import { CardFieldState } from './types'; +import type { WpcomCreditCardSelectors } from './store'; import type { ManagedContactDetails } from '@automattic/wpcom-checkout'; export default function ContactFields( { @@ -21,7 +23,10 @@ export default function ContactFields( { const { formStatus } = useFormStatus(); const isDisabled = formStatus !== FormStatus.READY; const countriesList = useCountryList(); - const fields = useSelect( ( select ) => select( 'wpcom-credit-card' ).getFields() ); + const fields: CardFieldState = useSelect( + ( select ) => ( select( 'wpcom-credit-card' ) as WpcomCreditCardSelectors ).getFields(), + [] + ); const onChangeContactInfo = ( newInfo: ManagedContactDetails ) => { setFieldValue( 'countryCode', newInfo.countryCode?.value ?? '' ); setFieldValue( 'postalCode', newInfo.postalCode?.value ?? '' ); diff --git a/client/my-sites/checkout/composite-checkout/payment-methods/credit-card/credit-card-cvv-field.tsx b/client/my-sites/checkout/composite-checkout/payment-methods/credit-card/credit-card-cvv-field.tsx index 3547d415a1ab2..7e8f7cdd8642b 100644 --- a/client/my-sites/checkout/composite-checkout/payment-methods/credit-card/credit-card-cvv-field.tsx +++ b/client/my-sites/checkout/composite-checkout/payment-methods/credit-card/credit-card-cvv-field.tsx @@ -15,6 +15,7 @@ import { StripeFieldWrapper, StripeErrorMessage, } from './form-layout-components'; +import type { WpcomCreditCardSelectors } from './store'; import type { StripeFieldChangeInput } from './types'; import type { StripeElementStyle } from '@stripe/stripe-js'; @@ -36,8 +37,9 @@ export default function CreditCardCvvField( { const translate = useTranslate(); const { formStatus } = useFormStatus(); const isDisabled = formStatus !== FormStatus.READY; - const { cardCvc: cardCvcError } = useSelect( ( select ) => - select( 'wpcom-credit-card' ).getCardDataErrors() + const { cardCvc: cardCvcError } = useSelect( + ( select ) => ( select( 'wpcom-credit-card' ) as WpcomCreditCardSelectors ).getCardDataErrors(), + [] ); const errorMessages = getErrorMessagesForField( 'cvv' ); const errorMessage = errorMessages?.length > 0 ? errorMessages[ 0 ] : null; diff --git a/client/my-sites/checkout/composite-checkout/payment-methods/credit-card/credit-card-expiry-field.tsx b/client/my-sites/checkout/composite-checkout/payment-methods/credit-card/credit-card-expiry-field.tsx index 46bedd92d2916..016e0b6c48083 100644 --- a/client/my-sites/checkout/composite-checkout/payment-methods/credit-card/credit-card-expiry-field.tsx +++ b/client/my-sites/checkout/composite-checkout/payment-methods/credit-card/credit-card-expiry-field.tsx @@ -4,6 +4,7 @@ import { useSelect } from '@wordpress/data'; import { useTranslate } from 'i18n-calypso'; import { Input } from 'calypso/my-sites/domains/components/form'; import { Label, LabelText, StripeFieldWrapper, StripeErrorMessage } from './form-layout-components'; +import type { WpcomCreditCardSelectors } from './store'; import type { StripeFieldChangeInput } from './types'; import type { StripeElementStyle } from '@stripe/stripe-js'; @@ -25,8 +26,9 @@ export default function CreditCardExpiryField( { const translate = useTranslate(); const { formStatus } = useFormStatus(); const isDisabled = formStatus !== FormStatus.READY; - const { cardExpiry: cardExpiryError } = useSelect( ( select ) => - select( 'wpcom-credit-card' ).getCardDataErrors() + const { cardExpiry: cardExpiryError } = useSelect( + ( select ) => ( select( 'wpcom-credit-card' ) as WpcomCreditCardSelectors ).getCardDataErrors(), + [] ); const errorMessages = getErrorMessagesForField( 'expiration-date' ); const errorMessage = errorMessages?.length > 0 ? errorMessages[ 0 ] : null; diff --git a/client/my-sites/checkout/composite-checkout/payment-methods/credit-card/credit-card-fields.tsx b/client/my-sites/checkout/composite-checkout/payment-methods/credit-card/credit-card-fields.tsx index da7bc7144c81d..08d46047024fe 100644 --- a/client/my-sites/checkout/composite-checkout/payment-methods/credit-card/credit-card-fields.tsx +++ b/client/my-sites/checkout/composite-checkout/payment-methods/credit-card/credit-card-fields.tsx @@ -18,7 +18,8 @@ import CreditCardExpiryField from './credit-card-expiry-field'; import CreditCardLoading from './credit-card-loading'; import CreditCardNumberField from './credit-card-number-field'; import { FieldRow, CreditCardFieldsWrapper, CreditCardField } from './form-layout-components'; -import type { StripeFieldChangeInput } from './types'; +import type { WpcomCreditCardSelectors } from './store'; +import type { CardFieldState, StripeFieldChangeInput } from './types'; const StripeFields = styled.div` position: relative; @@ -47,9 +48,14 @@ export default function CreditCardFields( { const { __ } = useI18n(); const theme = useTheme(); const [ isStripeFullyLoaded, setIsStripeFullyLoaded ] = useState( false ); - const fields = useSelect( ( select ) => select( 'wpcom-credit-card' ).getFields() ); - const useForAllSubscriptions = useSelect( ( select ) => - select( 'wpcom-credit-card' ).useForAllSubscriptions() + const fields: CardFieldState = useSelect( + ( select ) => ( select( 'wpcom-credit-card' ) as WpcomCreditCardSelectors ).getFields(), + [] + ); + const useForAllSubscriptions: boolean = useSelect( + ( select ) => + ( select( 'wpcom-credit-card' ) as WpcomCreditCardSelectors ).useForAllSubscriptions(), + [] ); const getField = ( key: string ) => fields[ key ] || {}; const getFieldValue = ( key: string ) => getField( key ).value ?? ''; diff --git a/client/my-sites/checkout/composite-checkout/payment-methods/credit-card/credit-card-number-field.tsx b/client/my-sites/checkout/composite-checkout/payment-methods/credit-card/credit-card-number-field.tsx index d74eebfa5d5ef..29f98616ca5f1 100644 --- a/client/my-sites/checkout/composite-checkout/payment-methods/credit-card/credit-card-number-field.tsx +++ b/client/my-sites/checkout/composite-checkout/payment-methods/credit-card/credit-card-number-field.tsx @@ -4,6 +4,7 @@ import { useSelect } from '@wordpress/data'; import { useI18n } from '@wordpress/react-i18n'; import CreditCardNumberInput from 'calypso/components/upgrades/credit-card-number-input'; import { Label, LabelText, StripeFieldWrapper, StripeErrorMessage } from './form-layout-components'; +import type { WpcomCreditCardSelectors } from './store'; import type { StripeFieldChangeInput } from './types'; import type { StripeElementStyle } from '@stripe/stripe-js'; @@ -27,9 +28,13 @@ export default function CreditCardNumberField( { const { __ } = useI18n(); const { formStatus } = useFormStatus(); const isDisabled = formStatus !== FormStatus.READY; - const brand = useSelect( ( select ) => select( 'wpcom-credit-card' ).getBrand() ); - const { cardNumber: cardNumberError } = useSelect( ( select ) => - select( 'wpcom-credit-card' ).getCardDataErrors() + const brand: string = useSelect( + ( select ) => ( select( 'wpcom-credit-card' ) as WpcomCreditCardSelectors ).getBrand(), + [] + ); + const { cardNumber: cardNumberError } = useSelect( + ( select ) => ( select( 'wpcom-credit-card' ) as WpcomCreditCardSelectors ).getCardDataErrors(), + [] ); const errorMessages = getErrorMessagesForField( 'number' ); const errorMessage = errorMessages?.length > 0 ? errorMessages[ 0 ] : null; diff --git a/client/my-sites/checkout/composite-checkout/payment-methods/credit-card/credit-card-pay-button.tsx b/client/my-sites/checkout/composite-checkout/payment-methods/credit-card/credit-card-pay-button.tsx index b6f424aa7dab9..dd2dac102daeb 100644 --- a/client/my-sites/checkout/composite-checkout/payment-methods/credit-card/credit-card-pay-button.tsx +++ b/client/my-sites/checkout/composite-checkout/payment-methods/credit-card/credit-card-pay-button.tsx @@ -7,7 +7,8 @@ import { useI18n } from '@wordpress/react-i18n'; import debugFactory from 'debug'; import { validatePaymentDetails } from 'calypso/lib/checkout/validation'; import { actions, selectors } from './store'; -import type { CardStoreType } from './types'; +import type { WpcomCreditCardSelectors } from './store'; +import type { CardFieldState, CardStoreType } from './types'; import type { ProcessPayment, LineItem } from '@automattic/composite-checkout'; const debug = debugFactory( 'calypso:composite-checkout:credit-card' ); @@ -28,9 +29,14 @@ export default function CreditCardPayButton( { const { __ } = useI18n(); const total = useTotal(); const { stripeConfiguration, stripe } = useStripe(); - const fields = useSelect( ( select ) => select( 'wpcom-credit-card' ).getFields() ); - const useForAllSubscriptions = useSelect( ( select ) => - select( 'wpcom-credit-card' ).useForAllSubscriptions() + const fields: CardFieldState = useSelect( + ( select ) => ( select( 'wpcom-credit-card' ) as WpcomCreditCardSelectors ).getFields(), + [] + ); + const useForAllSubscriptions = useSelect( + ( select ) => + ( select( 'wpcom-credit-card' ) as WpcomCreditCardSelectors ).useForAllSubscriptions(), + [] ); const cardholderName = fields.cardholderName; const { formStatus } = useFormStatus(); diff --git a/client/my-sites/checkout/composite-checkout/payment-methods/credit-card/index.tsx b/client/my-sites/checkout/composite-checkout/payment-methods/credit-card/index.tsx index 4e4df989cb6a7..a4ccefc7bb072 100644 --- a/client/my-sites/checkout/composite-checkout/payment-methods/credit-card/index.tsx +++ b/client/my-sites/checkout/composite-checkout/payment-methods/credit-card/index.tsx @@ -14,7 +14,8 @@ import { } from 'calypso/my-sites/checkout/composite-checkout/components/summary-details'; import CreditCardFields from './credit-card-fields'; import CreditCardPayButton from './credit-card-pay-button'; -import type { CardStoreType } from './types'; +import type { WpcomCreditCardSelectors } from './store'; +import type { CardFieldState, CardStoreType } from './types'; export { createCreditCardPaymentMethodStore } from './store'; @@ -55,9 +56,15 @@ export function createCreditCardMethod( { } function CreditCardSummary() { - const fields = useSelect( ( select ) => select( 'wpcom-credit-card' ).getFields() ); + const fields: CardFieldState = useSelect( + ( select ) => ( select( 'wpcom-credit-card' ) as WpcomCreditCardSelectors ).getFields(), + [] + ); const cardholderName = fields.cardholderName; - const brand = useSelect( ( select ) => select( 'wpcom-credit-card' ).getBrand() ); + const brand: string = useSelect( + ( select ) => ( select( 'wpcom-credit-card' ) as WpcomCreditCardSelectors ).getBrand(), + [] + ); return ( diff --git a/client/my-sites/checkout/composite-checkout/payment-methods/credit-card/store.ts b/client/my-sites/checkout/composite-checkout/payment-methods/credit-card/store.ts index f8b5c67056d16..a43902b4fb183 100644 --- a/client/my-sites/checkout/composite-checkout/payment-methods/credit-card/store.ts +++ b/client/my-sites/checkout/composite-checkout/payment-methods/credit-card/store.ts @@ -8,16 +8,12 @@ import type { CardStoreAction, CardElementType, } from './types'; -import type { DispatchFromMap, SelectFromMap } from '@automattic/data-stores'; +import type { SelectFromMap } from '@automattic/data-stores'; import type { StoreStateValue } from '@automattic/wpcom-checkout'; +import type { AnyAction } from 'redux'; const debug = debugFactory( 'calypso:composite-checkout:credit-card' ); -declare module '@wordpress/data' { - function dispatch( key: 'wpcom-credit-card' ): DispatchFromMap< typeof actions >; - function select( key: 'wpcom-credit-card' ): SelectFromMap< typeof selectors >; -} - export const actions = { changeBrand( payload: string ): CardStoreAction { return { type: 'BRAND_SET', payload }; @@ -62,6 +58,8 @@ export const selectors = { }, }; +export type WpcomCreditCardSelectors = SelectFromMap< typeof selectors >; + export function createCreditCardPaymentMethodStore( { initialUseForAllSubscriptions, allowUseForAllSubscriptions, @@ -174,7 +172,7 @@ export function createCreditCardPaymentMethodStore( { brand: brandReducer(), useForAllSubscriptions: getInitialUseForAllSubscriptionsValue(), }, - action + action: AnyAction ) { return { fields: fieldReducer( state.fields, action ), diff --git a/client/my-sites/checkout/composite-checkout/payment-methods/credit-card/types.ts b/client/my-sites/checkout/composite-checkout/payment-methods/credit-card/types.ts index 19dbafa978831..c47797e37a94f 100644 --- a/client/my-sites/checkout/composite-checkout/payment-methods/credit-card/types.ts +++ b/client/my-sites/checkout/composite-checkout/payment-methods/credit-card/types.ts @@ -1,5 +1,17 @@ import type { StoreState } from '@automattic/wpcom-checkout'; -import type { Store } from '@wordpress/data'; +import type { StoreDescriptor } from '@wordpress/data'; +import type { AnyAction as Action } from 'redux'; + +export type CardSubscriber = ( + callback: () => void, + storeNameOrDescriptor?: string | StoreDescriptor +) => () => void; + +export interface CardStore< S, A extends Action = Action > { + getState(): S; + subscribe: CardSubscriber; + dispatch( action: A ): A; +} export type CardFieldState = StoreState< string >; @@ -13,7 +25,7 @@ export interface CardStoreState { useForAllSubscriptions: boolean; } -export type CardStoreType = Store< CardStoreState, CardStoreAction >; +export type CardStoreType = CardStore< CardStoreState, CardStoreAction >; export type CardNumberElementType = 'cardNumber'; export type CardExpiryElementType = 'cardExpiry'; diff --git a/client/my-sites/checkout/composite-checkout/payment-methods/netbanking.tsx b/client/my-sites/checkout/composite-checkout/payment-methods/netbanking.tsx index 345ba880e889d..51432685b3f45 100644 --- a/client/my-sites/checkout/composite-checkout/payment-methods/netbanking.tsx +++ b/client/my-sites/checkout/composite-checkout/payment-methods/netbanking.tsx @@ -2,7 +2,7 @@ import { Button, FormStatus, useTotal, useFormStatus } from '@automattic/composi import { snakeToCamelCase } from '@automattic/js-utils'; import { Field } from '@automattic/wpcom-checkout'; import styled from '@emotion/styled'; -import { useSelect, useDispatch, registerStore } from '@wordpress/data'; +import { useSelect, useDispatch, register, registerStore } from '@wordpress/data'; import { sprintf } from '@wordpress/i18n'; import { useI18n } from '@wordpress/react-i18n'; import debugFactory from 'debug'; @@ -25,31 +25,25 @@ import type { StoreStateValue, } from '@automattic/wpcom-checkout'; import type { CalypsoDispatch } from 'calypso/state/types'; +import type { AnyAction } from 'redux'; const debug = debugFactory( 'composite-checkout:netbanking-payment-method' ); // Disabling this to make migration easier /* eslint-disable @typescript-eslint/no-use-before-define */ -type StoreKey = 'netbanking'; type NounsInStore = 'customerName'; type FieldsType = Record< string, StoreStateValue >; type NetBankingStoreState< N extends string > = Record< N, StoreStateValue > & { fields: FieldsType; }; -interface NetBankingPaymentMethodStore< N extends string > - extends ReturnType< typeof registerStore > { +interface NetBankingPaymentMethodStore< N extends string > extends ReturnType< typeof register > { getState: () => NetBankingStoreState< N >; } type NetBankingStore = NetBankingPaymentMethodStore< NounsInStore >; -declare module '@wordpress/data' { - function select( - key: StoreKey - ): StoreSelectors< NounsInStore > & { getFields: () => FieldsType }; - function dispatch( key: StoreKey ): typeof actions; -} +type NetBankingSelectors = StoreSelectors< NounsInStore > & { getFields: () => FieldsType }; const actions = { changeCustomerName( payload: string ) { @@ -81,11 +75,11 @@ export function createNetBankingPaymentMethodStore(): NetBankingStore { debug( 'creating a new netbanking payment method store' ); const store = registerStore( 'netbanking', { reducer( - state = { + state: NetBankingStoreState< NounsInStore > = { customerName: { value: '', isTouched: false }, fields: {}, }, - action + action: AnyAction ) { switch ( action.type ) { case 'CUSTOMER_NAME_SET': @@ -155,7 +149,10 @@ export function createNetBankingMethod( { store }: { store: NetBankingStore } ): function NetBankingFields() { const { __ } = useI18n(); - const fields = useSelect( ( select ) => select( 'netbanking' ).getFields() ); + const fields = useSelect( + ( select ) => ( select( 'netbanking' ) as NetBankingSelectors ).getFields(), + [] + ); const getField = ( key: string ) => fields[ key ] || {}; const getFieldValue = ( key: string ) => getField( key ).value ?? ''; const getErrorMessagesForField = ( key: string ) => { @@ -164,7 +161,10 @@ function NetBankingFields() { }; const { setFieldValue } = useDispatch( 'netbanking' ); - const customerName = useSelect( ( select ) => select( 'netbanking' ).getCustomerName() ); + const customerName = useSelect( + ( select ) => ( select( 'netbanking' ) as NetBankingSelectors ).getCustomerName(), + [] + ); const { changeCustomerName } = useDispatch( 'netbanking' ); const { formStatus } = useFormStatus(); const isDisabled = formStatus !== FormStatus.READY; @@ -238,8 +238,14 @@ function NetBankingPayButton( { const { __ } = useI18n(); const total = useTotal(); const { formStatus } = useFormStatus(); - const customerName = useSelect( ( select ) => select( 'netbanking' ).getCustomerName() ); - const fields = useSelect( ( select ) => select( 'netbanking' ).getFields() ); + const customerName = useSelect( + ( select ) => ( select( 'netbanking' ) as NetBankingSelectors ).getCustomerName(), + [] + ); + const fields = useSelect( + ( select ) => ( select( 'netbanking' ) as NetBankingSelectors ).getFields(), + [] + ); const massagedFields: typeof fields = Object.entries( fields ).reduce( ( accum, [ key, managedValue ] ) => ( { ...accum, @@ -294,7 +300,10 @@ function ButtonContents( { formStatus, total }: { formStatus: FormStatus; total: } function NetBankingSummary() { - const customerName = useSelect( ( select ) => select( 'netbanking' ).getCustomerName() ); + const customerName = useSelect( + ( select ) => ( select( 'netbanking' ) as NetBankingSelectors ).getCustomerName(), + [] + ); return ( diff --git a/client/my-sites/checkout/composite-checkout/payment-methods/paypal.tsx b/client/my-sites/checkout/composite-checkout/payment-methods/paypal.tsx index 3f94a05272d58..22416cf57d7e3 100644 --- a/client/my-sites/checkout/composite-checkout/payment-methods/paypal.tsx +++ b/client/my-sites/checkout/composite-checkout/payment-methods/paypal.tsx @@ -23,6 +23,7 @@ import type { StoreState, ManagedContactDetails, } from '@automattic/wpcom-checkout'; +import type { AnyAction } from 'redux'; const debug = debugFactory( 'calypso:paypal-payment-method' ); @@ -30,14 +31,10 @@ const debug = debugFactory( 'calypso:paypal-payment-method' ); /* eslint-disable @typescript-eslint/no-use-before-define */ const storeKey = 'paypal'; -type StoreKey = typeof storeKey; type NounsInStore = 'postalCode' | 'countryCode' | 'address1' | 'organization' | 'city' | 'state'; -type PayPalStore = PaymentMethodStore< NounsInStore >; +type PaypalSelectors = StoreSelectors< NounsInStore >; -declare module '@wordpress/data' { - function select( key: StoreKey ): StoreSelectors< NounsInStore >; - function dispatch( key: StoreKey ): StoreActions< NounsInStore >; -} +type PayPalStore = PaymentMethodStore< NounsInStore >; const actions: StoreActions< NounsInStore > = { changePostalCode( payload ) { @@ -93,7 +90,7 @@ export function createPayPalStore(): PayPalStore { city: { value: '', isTouched: false }, state: { value: '', isTouched: false }, }, - action + action: AnyAction ): StoreState< NounsInStore > { switch ( action.type ) { case 'POSTAL_CODE_SET': @@ -177,12 +174,24 @@ function PayPalTaxFields() { const { formStatus } = useFormStatus(); const isDisabled = formStatus !== FormStatus.READY; const countriesList = useCountryList(); - const postalCode = useSelect( ( select ) => select( storeKey ).getPostalCode() ); - const countryCode = useSelect( ( select ) => select( storeKey ).getCountryCode() ); - const address1 = useSelect( ( select ) => select( storeKey ).getAddress1() ); - const organization = useSelect( ( select ) => select( storeKey ).getOrganization() ); - const city = useSelect( ( select ) => select( storeKey ).getCity() ); - const state = useSelect( ( select ) => select( storeKey ).getState() ); + const postalCode = useSelect( + ( select ) => ( select( storeKey ) as PaypalSelectors ).getPostalCode(), + [] + ); + const countryCode = useSelect( + ( select ) => ( select( storeKey ) as PaypalSelectors ).getCountryCode(), + [] + ); + const address1 = useSelect( + ( select ) => ( select( storeKey ) as PaypalSelectors ).getAddress1(), + [] + ); + const organization = useSelect( + ( select ) => ( select( storeKey ) as PaypalSelectors ).getOrganization(), + [] + ); + const city = useSelect( ( select ) => ( select( storeKey ) as PaypalSelectors ).getCity(), [] ); + const state = useSelect( ( select ) => ( select( storeKey ) as PaypalSelectors ).getState(), [] ); const fields = useMemo( () => ( { postalCode: { ...postalCode, errors: [] }, @@ -244,8 +253,14 @@ function PayPalLabel( { } function TaxLabel() { - const postalCode = useSelect( ( select ) => select( storeKey ).getPostalCode() ); - const countryCode = useSelect( ( select ) => select( storeKey ).getCountryCode() ); + const postalCode = useSelect( + ( select ) => ( select( storeKey ) as PaypalSelectors ).getPostalCode(), + [] + ); + const countryCode = useSelect( + ( select ) => ( select( storeKey ) as PaypalSelectors ).getCountryCode(), + [] + ); const taxString = [ countryCode.value, postalCode.value ].filter( isValueTruthy ).join( ', ' ); return (
@@ -264,12 +279,24 @@ function PayPalSubmitButton( { const { __ } = useI18n(); const { formStatus } = useFormStatus(); const { transactionStatus } = useTransactionStatus(); - const postalCode = useSelect( ( select ) => select( storeKey )?.getPostalCode() ); - const countryCode = useSelect( ( select ) => select( storeKey )?.getCountryCode() ); - const address1 = useSelect( ( select ) => select( storeKey )?.getAddress1() ); - const organization = useSelect( ( select ) => select( storeKey )?.getOrganization() ); - const city = useSelect( ( select ) => select( storeKey ).getCity() ); - const state = useSelect( ( select ) => select( storeKey ).getState() ); + const postalCode = useSelect( + ( select ) => ( select( storeKey ) as PaypalSelectors ).getPostalCode(), + [] + ); + const countryCode = useSelect( + ( select ) => ( select( storeKey ) as PaypalSelectors ).getCountryCode(), + [] + ); + const address1 = useSelect( + ( select ) => ( select( storeKey ) as PaypalSelectors ).getAddress1(), + [] + ); + const organization = useSelect( + ( select ) => ( select( storeKey ) as PaypalSelectors ).getOrganization(), + [] + ); + const city = useSelect( ( select ) => ( select( storeKey ) as PaypalSelectors ).getCity(), [] ); + const state = useSelect( ( select ) => ( select( storeKey ) as PaypalSelectors ).getState(), [] ); const handleButtonPress = () => { if ( ! onClick ) { diff --git a/client/my-sites/checkout/composite-checkout/payment-methods/wechat/index.tsx b/client/my-sites/checkout/composite-checkout/payment-methods/wechat/index.tsx index d491600396be9..71e71929b1493 100644 --- a/client/my-sites/checkout/composite-checkout/payment-methods/wechat/index.tsx +++ b/client/my-sites/checkout/composite-checkout/payment-methods/wechat/index.tsx @@ -29,18 +29,13 @@ import type { StoreActions, StoreState, } from '@automattic/wpcom-checkout'; +import type { AnyAction } from 'redux'; const debug = debugFactory( 'calypso:composite-checkout:wechat-payment-method' ); -type StoreKey = 'wechat'; type NounsInStore = 'customerName'; type WeChatStore = PaymentMethodStore< NounsInStore >; -declare module '@wordpress/data' { - function select( key: StoreKey ): StoreSelectors< NounsInStore >; - function dispatch( key: StoreKey ): StoreActions< NounsInStore >; -} - interface WeChatStripeResponse { order_id: number; redirect_url: string; @@ -65,7 +60,7 @@ export function createWeChatPaymentMethodStore(): WeChatStore { state: StoreState< NounsInStore > = { customerName: { value: '', isTouched: false }, }, - action + action: AnyAction ) { switch ( action.type ) { case 'CUSTOMER_NAME_SET': @@ -148,7 +143,10 @@ const WeChatPaymentQRcode = styled( WeChatPaymentQRcodeUnstyled )` function WeChatFields() { const { __ } = useI18n(); - const customerName = useSelect( ( select ) => select( 'wechat' ).getCustomerName() ); + const customerName = useSelect( + ( select ) => ( select( 'wechat' ) as StoreSelectors< NounsInStore > ).getCustomerName(), + [] + ); const { changeCustomerName } = useDispatch( 'wechat' ); const { formStatus } = useFormStatus(); const isDisabled = formStatus !== FormStatus.READY; @@ -184,7 +182,10 @@ function WeChatPayButton( { const total = useTotal(); const { formStatus } = useFormStatus(); const { resetTransaction } = useTransactionStatus(); - const customerName = useSelect( ( select ) => select( 'wechat' ).getCustomerName() ); + const customerName = useSelect( + ( select ) => ( select( 'wechat' ) as StoreSelectors< NounsInStore > ).getCustomerName(), + [] + ); const cartKey = useCartKey(); const { responseCart: cart } = useShoppingCart( cartKey ); const [ stripeResponseWithCode, setStripeResponseWithCode ] = @@ -259,7 +260,10 @@ function ButtonContents( { } function WeChatSummary() { - const customerName = useSelect( ( select ) => select( 'wechat' ).getCustomerName() ); + const customerName = useSelect( + ( select ) => ( select( 'wechat' ) as StoreSelectors< NounsInStore > ).getCustomerName(), + [] + ); return ( diff --git a/client/my-sites/customer-home/cards/features/domain-upsell/index.jsx b/client/my-sites/customer-home/cards/features/domain-upsell/index.jsx index c0dcdedabf51e..3b785e122e062 100644 --- a/client/my-sites/customer-home/cards/features/domain-upsell/index.jsx +++ b/client/my-sites/customer-home/cards/features/domain-upsell/index.jsx @@ -89,6 +89,10 @@ export default function DomainUpsell( { context } ) { ); } +const domainSuggestionOptions = { + vendor: 'domain-upsell', +}; + export function RenderDomainUpsell( { isFreePlan, isMonthlyPlan, @@ -103,10 +107,11 @@ export function RenderDomainUpsell( { const dispatch = useDispatch(); const locale = useLocale(); + + // Note: domainSuggestionOptions must be equal by reference upon each render + // to avoid a render loop, since it's used to memoize a selector. const { allDomainSuggestions } = - useDomainSuggestions( searchTerm, 3, undefined, locale, { - vendor: 'domain-upsell', - } ) || {}; + useDomainSuggestions( searchTerm, 3, undefined, locale, domainSuggestionOptions ) || {}; const cartKey = useCartKey(); const shoppingCartManager = useShoppingCart( cartKey ); diff --git a/client/my-sites/plans/components/domain-upsell-dialog/index.tsx b/client/my-sites/plans/components/domain-upsell-dialog/index.tsx index 4feb9717b7383..1f8eaaafe8b33 100644 --- a/client/my-sites/plans/components/domain-upsell-dialog/index.tsx +++ b/client/my-sites/plans/components/domain-upsell-dialog/index.tsx @@ -9,6 +9,7 @@ import { getSiteSlug } from 'calypso/state/sites/selectors'; import { getSelectedSiteId } from 'calypso/state/ui/selectors'; import { WPCOM_PLANS_UI_STORE } from '../../store'; import './style.scss'; +import type { WpcomPlansUISelect } from '@automattic/data-stores'; const DomainUpsellDialog: React.FunctionComponent< { domain: string; @@ -18,8 +19,8 @@ const DomainUpsellDialog: React.FunctionComponent< { const siteSlug = useSelector( ( state ) => getSiteSlug( state, selectedSiteId ) ); const { setShowDomainUpsellDialog } = useDispatch( WPCOM_PLANS_UI_STORE ); const isVisible = useSelect( ( select ) => { - return select( WPCOM_PLANS_UI_STORE ).isDomainUpsellDialogShown(); - } ); + return ( select( WPCOM_PLANS_UI_STORE ) as WpcomPlansUISelect ).isDomainUpsellDialogShown(); + }, [] ); const onCloseDialog = useCallback( () => { setShowDomainUpsellDialog( false ); diff --git a/client/my-sites/plugins/plugin-management-v2/test/plugin-row-formatter.test.tsx b/client/my-sites/plugins/plugin-management-v2/test/plugin-row-formatter.test.tsx index 5962d037ad41c..5469c65040e18 100644 --- a/client/my-sites/plugins/plugin-management-v2/test/plugin-row-formatter.test.tsx +++ b/client/my-sites/plugins/plugin-management-v2/test/plugin-row-formatter.test.tsx @@ -48,6 +48,18 @@ const props = { }; describe( '', () => { + beforeAll( () => { + window.matchMedia = jest.fn().mockImplementation( ( query ) => { + return { + matches: true, + media: query, + onchange: null, + addListener: jest.fn(), + removeListener: jest.fn(), + }; + } ); + } ); + test( 'should render correctly and show site domain', () => { const { container } = render( ); diff --git a/client/my-sites/purchases/subscriptions/subscriptions-content.tsx b/client/my-sites/purchases/subscriptions/subscriptions-content.tsx index b22f2abc841ae..0ae52066dc9b1 100644 --- a/client/my-sites/purchases/subscriptions/subscriptions-content.tsx +++ b/client/my-sites/purchases/subscriptions/subscriptions-content.tsx @@ -15,7 +15,7 @@ import { } from 'calypso/state/purchases/selectors'; import { getAllStoredCards } from 'calypso/state/stored-cards/selectors'; import { getSelectedSite, getSelectedSiteId } from 'calypso/state/ui/selectors'; -import type { SiteDetails } from 'calypso/../packages/data-stores/src'; +import type { SiteDetails } from '@automattic/data-stores'; import type { StoredCard } from 'calypso/my-sites/checkout/composite-checkout/types/stored-cards'; import './style.scss'; diff --git a/client/my-sites/site-settings/test/form-cloudflare-analytics.jsx b/client/my-sites/site-settings/test/form-cloudflare-analytics.jsx index ab9eda3985265..406f7501cc3be 100644 --- a/client/my-sites/site-settings/test/form-cloudflare-analytics.jsx +++ b/client/my-sites/site-settings/test/form-cloudflare-analytics.jsx @@ -21,6 +21,18 @@ const props = { }; describe( 'CloudflareAnalyticsSettings basic tests', () => { + beforeAll( () => { + window.matchMedia = jest.fn().mockImplementation( ( query ) => { + return { + matches: true, + media: query, + onchange: null, + addListener: jest.fn(), + removeListener: jest.fn(), + }; + } ); + } ); + test( 'Cloudflare form should not show upgrade nudge if disabled', () => { render( ); expect( screen.queryByTestId( 'UpsellNudge' ) ).not.toBeInTheDocument(); diff --git a/client/my-sites/site-settings/test/form-google-analytics.jsx b/client/my-sites/site-settings/test/form-google-analytics.jsx index 93dd9f884aafd..46b926317843a 100644 --- a/client/my-sites/site-settings/test/form-google-analytics.jsx +++ b/client/my-sites/site-settings/test/form-google-analytics.jsx @@ -45,6 +45,18 @@ const props = { }; describe( 'GoogleAnalyticsForm basic tests', () => { + beforeAll( () => { + window.matchMedia = jest.fn().mockImplementation( ( query ) => { + return { + matches: true, + media: query, + onchange: null, + addListener: jest.fn(), + removeListener: jest.fn(), + }; + } ); + } ); + test( 'simple form should not blow up and have proper CSS class', () => { render( ); expect( screen.queryByRole( 'form', { name: /analytics/i } ) ).toBeVisible(); diff --git a/client/package.json b/client/package.json index 0e0696e4654d6..8643dd761ffa7 100644 --- a/client/package.json +++ b/client/package.json @@ -76,29 +76,29 @@ "@sentry/react": "^7.33.0", "@stripe/react-stripe-js": "^1.4.1", "@stripe/stripe-js": "1.17.1", - "@wordpress/a11y": "^3.9.0", - "@wordpress/api-fetch": "^6.6.0", - "@wordpress/base-styles": "^4.7.0", - "@wordpress/block-editor": "^9.1.0", - "@wordpress/blocks": "^11.8.0", - "@wordpress/components": "^19.15.0", - "@wordpress/compose": "^5.7.0", - "@wordpress/data": "^6.9.0", - "@wordpress/data-controls": "^2.9.0", - "@wordpress/edit-post": "^6.6.0", - "@wordpress/element": "^4.7.0", - "@wordpress/format-library": "^3.7.0", - "@wordpress/hooks": "^3.9.0", - "@wordpress/html-entities": "^3.9.0", - "@wordpress/i18n": "^4.9.0", - "@wordpress/icons": "^9.0.0", - "@wordpress/is-shallow-equal": "^4.9.0", - "@wordpress/keyboard-shortcuts": "^3.7.0", - "@wordpress/keycodes": "^3.9.0", - "@wordpress/react-i18n": "^3.7.0", - "@wordpress/url": "^3.10.0", - "@wordpress/viewport": "^4.7.0", - "@wordpress/warning": "^2.9.0", + "@wordpress/a11y": "^3.22.0", + "@wordpress/api-fetch": "^6.19.0", + "@wordpress/base-styles": "^4.13.0", + "@wordpress/block-editor": "^10.5.0", + "@wordpress/blocks": "^11.21.0", + "@wordpress/components": "^22.1.0", + "@wordpress/compose": "^5.20.0", + "@wordpress/data": "^7.6.0", + "@wordpress/data-controls": "^2.22.0", + "@wordpress/edit-post": "^6.19.0", + "@wordpress/element": "^4.20.0", + "@wordpress/format-library": "^3.20.0", + "@wordpress/hooks": "^3.22.0", + "@wordpress/html-entities": "^3.22.0", + "@wordpress/i18n": "^4.22.0", + "@wordpress/icons": "^9.13.0", + "@wordpress/is-shallow-equal": "^4.22.0", + "@wordpress/keyboard-shortcuts": "^3.20.0", + "@wordpress/keycodes": "^3.22.0", + "@wordpress/react-i18n": "^3.20.0", + "@wordpress/url": "^3.23.0", + "@wordpress/viewport": "^4.20.0", + "@wordpress/warning": "^2.22.0", "autosize": "^4.0.4", "body-parser": "^1.19.0", "browser-filesaver": "^1.1.1", diff --git a/client/state/partner-portal/credit-card-form/index.ts b/client/state/partner-portal/credit-card-form/index.ts index 8a2f8e50f478d..76d6df2f387f4 100644 --- a/client/state/partner-portal/credit-card-form/index.ts +++ b/client/state/partner-portal/credit-card-form/index.ts @@ -2,7 +2,6 @@ import { registerStore } from '@wordpress/data'; import * as actions from 'calypso/state/partner-portal/credit-card-form/actions'; import reducer from 'calypso/state/partner-portal/credit-card-form/reducer'; import * as selectors from 'calypso/state/partner-portal/credit-card-form/selectors'; -import type { DispatchFromMap, SelectFromMap } from '@automattic/data-stores'; export function createStoredCreditCardPaymentMethodStore(): Record< string, unknown > { const store = registerStore( 'credit-card', { @@ -13,8 +12,3 @@ export function createStoredCreditCardPaymentMethodStore(): Record< string, unkn return { ...store, actions, selectors }; } - -declare module '@wordpress/data' { - function dispatch( key: 'credit-card' ): DispatchFromMap< typeof actions >; - function select( key: 'credit-card' ): SelectFromMap< typeof selectors >; -} diff --git a/client/state/partner-portal/types.ts b/client/state/partner-portal/types.ts index 2288a8a434b61..783220e74e4d4 100644 --- a/client/state/partner-portal/types.ts +++ b/client/state/partner-portal/types.ts @@ -5,6 +5,10 @@ import { LicenseSortDirection, LicenseSortField, } from 'calypso/jetpack-cloud/sections/partner-portal/types'; +import * as creditCardSelectors from './credit-card-form/selectors'; +import type { SelectFromMap } from '@automattic/data-stores'; + +export type CreditCardSelectors = SelectFromMap< typeof creditCardSelectors >; /** * Utility. diff --git a/client/state/sites/hooks/use-premium-global-styles.ts b/client/state/sites/hooks/use-premium-global-styles.ts index f8058d67b17d3..9f6c4da4b225f 100644 --- a/client/state/sites/hooks/use-premium-global-styles.ts +++ b/client/state/sites/hooks/use-premium-global-styles.ts @@ -9,13 +9,14 @@ import { getGlobalStylesInfoForSite, } from './use-site-global-styles-status'; import type { GlobalStylesStatus } from './use-site-global-styles-status'; +import type { OnboardSelect } from '@automattic/data-stores'; export function usePremiumGlobalStyles(): GlobalStylesStatus { const params = new URLSearchParams( window.location.search ); const siteSlugParam = params.get( 'siteSlug' ); const siteIdParam = params.get( 'siteId' ); const selectedSiteId = useSelector( getSelectedSiteId ); - const onboard = select( ONBOARD_STORE ).getState(); + const onboard = ( select( ONBOARD_STORE ) as OnboardSelect ).getState(); // When site id is null it means that the site hasn't been created yet. const siteId = useSelector( ( state ) => { diff --git a/package.json b/package.json index 70a2cea6040dc..525b6e8e62d48 100644 --- a/package.json +++ b/package.json @@ -167,23 +167,21 @@ "@types/validator": "^13.7.1", "@types/webpack-env": "^1.16.3", "@types/wordpress__api-fetch": "^3.2.4", - "@types/wordpress__block-editor": "^6.0.5", "@types/wordpress__block-library": "^2.6.1", "@types/wordpress__components": "^14.0.10", "@types/wordpress__compose": "^4.0.1", "@types/wordpress__data": "^4.6.10", "@types/wordpress__data-controls": "^2.2.0", - "@types/wordpress__editor": "^10.0.1", - "@wordpress/base-styles": "^4.5.0", - "@wordpress/components": "^19.15.0", - "@wordpress/data": "^6.9.0", - "@wordpress/element": "^4.7.0", - "@wordpress/i18n": "^4.9.0", - "@wordpress/icons": "^9.0.0", - "@wordpress/is-shallow-equal": "^4.9.0", - "@wordpress/jest-preset-default": "^8.2.0", - "@wordpress/primitives": "^3.8.0", - "@wordpress/url": "^3.10.0", + "@wordpress/base-styles": "^4.13.0", + "@wordpress/components": "^22.1.0", + "@wordpress/data": "^7.6.0", + "@wordpress/element": "^4.20.0", + "@wordpress/i18n": "^4.22.0", + "@wordpress/icons": "^9.13.0", + "@wordpress/is-shallow-equal": "^4.22.0", + "@wordpress/jest-preset-default": "^10.3.0", + "@wordpress/primitives": "^3.20.0", + "@wordpress/url": "^3.23.0", "browserslist": "^4.16.0", "calypso": "workspace:^", "calypso-codemods": "workspace:^", @@ -224,8 +222,8 @@ "@types/superagent": "^4.1.15", "@typescript-eslint/eslint-plugin": "^5.53.0", "@typescript-eslint/parser": "^5.53.0", - "@wordpress/eslint-plugin": "^12.3.0", - "@wordpress/stylelint-config": "^20.0.2", + "@wordpress/eslint-plugin": "^13.6.0", + "@wordpress/stylelint-config": "^21.5.0", "babel-loader": "^8.2.3", "bunyan": "^1.8.15", "capture-website": "^1.0.0", @@ -292,6 +290,10 @@ }, "resolutions": { "react-dates": "17.1.1", + "@types/wordpress__block-editor": "npm:noop-package@1.0.0", + "@types/wordpress__editor": "npm:noop-package@1.0.0", + "@types/wordpress__notices": "npm:noop-package@1.0.0", + "@types/wordpress__rich-text": "npm:noop-package@1.0.0", "@types/react": "^17.0.39", "newspack-components/@wordpress/base-styles": "4.5.0", "newspack-components/@wordpress/components": "19.15.0", @@ -299,7 +301,10 @@ "newspack-components/@wordpress/i18n": "4.9.0", "keytar@npm:7.7.0/node-addon-api": "3.1.0", "lzma-native": "^8.0.5", - "@wordpress/interface@^4.8.0": "patch:@wordpress/interface@npm%3A4.8.0#./.yarn/patches/@wordpress-interface-npm-4.8.0-8a39ad37cf.patch" + "@wordpress/base-styles": "4.13.0", + "@wordpress/interface@^4.8.0": "patch:@wordpress/interface@npm%3A4.8.0#./.yarn/patches/@wordpress-interface-npm-4.8.0-8a39ad37cf.patch", + "@wordpress/data-controls": "2.22.0", + "@wordpress/element": "4.20.0" }, "packageManager": "yarn@3.2.3", "dependenciesMeta": { diff --git a/packages/block-renderer/package.json b/packages/block-renderer/package.json index cedc7e114bb06..d4cafb8b76b7c 100644 --- a/packages/block-renderer/package.json +++ b/packages/block-renderer/package.json @@ -29,9 +29,9 @@ "watch": "tsc --build ./tsconfig.json --watch" }, "dependencies": { - "@wordpress/block-editor": "^9.1.0", - "@wordpress/compose": "^5.7.0", - "@wordpress/edit-site": "^4.6.0", + "@wordpress/block-editor": "^10.5.0", + "@wordpress/compose": "^5.20.0", + "@wordpress/edit-site": "^4.19.0", "classnames": "^2.3.1", "react-query": "^3.32.1", "tslib": "^2.3.0", @@ -45,9 +45,9 @@ "typescript": "^4.7.4" }, "peerDependencies": { - "@wordpress/data": "^6.7.0", - "@wordpress/element": "^4.5.0", - "@wordpress/i18n": "^4.7.0", + "@wordpress/data": "^7.6.0", + "@wordpress/element": "^4.20.0", + "@wordpress/i18n": "^4.22.0", "debug": "^4.3.3", "react": "^17.0.2", "react-dom": "^17.0.2", diff --git a/packages/calypso-babel-config/package.json b/packages/calypso-babel-config/package.json index 622df243017f8..370d650e81fd5 100644 --- a/packages/calypso-babel-config/package.json +++ b/packages/calypso-babel-config/package.json @@ -36,7 +36,7 @@ "@babel/register": "^7.17.0", "@babel/runtime": "^7.17.2", "@emotion/babel-plugin": "^11.3.0", - "@wordpress/babel-plugin-import-jsx-pragma": "^3.1.2", + "@wordpress/babel-plugin-import-jsx-pragma": "^4.5.0", "babel-plugin-dynamic-import-node": "^2.3.3", "babel-plugin-transform-react-remove-prop-types": "^0.4.24" } diff --git a/packages/calypso-build/package.json b/packages/calypso-build/package.json index f348ffc0f826b..e5075389ff921 100644 --- a/packages/calypso-build/package.json +++ b/packages/calypso-build/package.json @@ -38,8 +38,8 @@ "@babel/compat-data": "^7.17.0", "@babel/core": "^7.17.5", "@types/webpack-env": "^1.16.3", - "@wordpress/browserslist-config": "^4.1.2", - "@wordpress/dependency-extraction-webpack-plugin": "^3.5.0", + "@wordpress/browserslist-config": "^5.5.0", + "@wordpress/dependency-extraction-webpack-plugin": "^4.5.0", "autoprefixer": "^10.2.5", "babel-loader": "^8.2.3", "browserslist": "^4.8.2", diff --git a/packages/calypso-e2e/package.json b/packages/calypso-e2e/package.json index 7d74fc74f9ca8..4fe7d2c5e5596 100644 --- a/packages/calypso-e2e/package.json +++ b/packages/calypso-e2e/package.json @@ -34,7 +34,7 @@ "@types/jest": "^27.4.0", "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.1", - "@wordpress/i18n": "^4.9.0", + "@wordpress/i18n": "^4.22.0", "asana-phrase": "^0.0.8", "node-fetch": "^2.6.7", "typescript": "^4.7.4" diff --git a/packages/components/package.json b/packages/components/package.json index 5ef8975b5f6a0..0ac26712f5c36 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -31,9 +31,9 @@ "@automattic/data-stores": "workspace:^", "@automattic/search": "workspace:^", "@automattic/typography": "workspace:^", - "@wordpress/base-styles": "^4.5.0", - "@wordpress/components": "^19.15.0", - "@wordpress/icons": "^9.11.0", + "@wordpress/base-styles": "^4.13.0", + "@wordpress/components": "^22.1.0", + "@wordpress/icons": "^9.13.0", "canvas-confetti": "^1.6.0", "classnames": "^2.3.1", "framer-motion": "6.2.8", @@ -46,7 +46,7 @@ "wpcom-proxy-request": "workspace:^" }, "peerDependencies": { - "@wordpress/data": "^6.1.5", + "@wordpress/data": "^7.6.0", "react": "^17.0.2", "react-dom": "^17.0.2" }, diff --git a/packages/composite-checkout/package.json b/packages/composite-checkout/package.json index 4d68272a4693b..bfe1ae1fee879 100644 --- a/packages/composite-checkout/package.json +++ b/packages/composite-checkout/package.json @@ -38,8 +38,8 @@ "dependencies": { "@emotion/react": "^11.4.1", "@emotion/styled": "^11.3.0", - "@wordpress/i18n": "^4.9.0", - "@wordpress/react-i18n": "^3.7.0", + "@wordpress/i18n": "^4.22.0", + "@wordpress/react-i18n": "^3.20.0", "debug": "^4.3.3", "prop-types": "^15.7.2" }, diff --git a/packages/data-stores/package.json b/packages/data-stores/package.json index de281733a6ab6..479592d1cb643 100644 --- a/packages/data-stores/package.json +++ b/packages/data-stores/package.json @@ -35,10 +35,10 @@ "@automattic/format-currency": "workspace:^", "@automattic/happychat-connection": "workspace:^", "@automattic/shopping-cart": "workspace:^", - "@wordpress/api-fetch": "^6.6.0", - "@wordpress/data-controls": "^2.9.0", - "@wordpress/deprecated": "^3.9.0", - "@wordpress/url": "^3.10.0", + "@wordpress/api-fetch": "^6.19.0", + "@wordpress/data-controls": "^2.22.0", + "@wordpress/deprecated": "^3.22.0", + "@wordpress/url": "^3.23.0", "fast-json-stable-stringify": "^2.1.0", "i18n-calypso": "workspace:^", "qs": "^6.9.1", @@ -49,7 +49,7 @@ "validator": "^13.5.2" }, "peerDependencies": { - "@wordpress/data": "^6", + "@wordpress/data": "^7.6.0", "react": "^17.0.2", "react-dom": "^17.0.2" }, diff --git a/packages/data-stores/src/analyzer/index.ts b/packages/data-stores/src/analyzer/index.ts index 0f61793e75f40..99dd3310252ae 100644 --- a/packages/data-stores/src/analyzer/index.ts +++ b/packages/data-stores/src/analyzer/index.ts @@ -5,24 +5,18 @@ import { STORE_KEY } from './constants'; import reducer, { State } from './reducers'; import * as selectors from './selectors'; export * from './types'; -import type { DispatchFromMap, SelectFromMap } from '../mapped-types'; export type { State }; let isRegistered = false; export function register(): typeof STORE_KEY { if ( ! isRegistered ) { isRegistered = true; - registerStore< State >( STORE_KEY, { + registerStore( STORE_KEY, { actions: createActions(), - controls: controls as any, - reducer: reducer as any, + controls: controls, + reducer: reducer, selectors, } ); } return STORE_KEY; } - -declare module '@wordpress/data' { - function dispatch( key: typeof STORE_KEY ): DispatchFromMap< ReturnType< typeof createActions > >; - function select( key: typeof STORE_KEY ): SelectFromMap< typeof selectors >; -} diff --git a/packages/data-stores/src/analyzer/types.ts b/packages/data-stores/src/analyzer/types.ts index 2e3255ca49aad..afd29ef9bca27 100644 --- a/packages/data-stores/src/analyzer/types.ts +++ b/packages/data-stores/src/analyzer/types.ts @@ -1,5 +1,6 @@ import * as actions from './actions'; -import type { DispatchFromMap } from '../mapped-types'; +import * as selectors from './selectors'; +import type { DispatchFromMap, SelectFromMap } from '../mapped-types'; interface Color { name: string; @@ -35,3 +36,5 @@ export type ColorsState = { export interface Dispatch { dispatch: DispatchFromMap< typeof actions >; } + +export type AnalyzerSelect = SelectFromMap< typeof selectors >; diff --git a/packages/data-stores/src/auth/index.ts b/packages/data-stores/src/auth/index.ts index 4c4459b045716..70d94db087171 100644 --- a/packages/data-stores/src/auth/index.ts +++ b/packages/data-stores/src/auth/index.ts @@ -7,7 +7,6 @@ import { STORE_KEY } from './constants'; import { controls } from './controls'; import reducer, { State } from './reducer'; import * as selectors from './selectors'; -import type { DispatchFromMap, SelectFromMap } from '../mapped-types'; export * from './types'; export type { State }; @@ -21,21 +20,16 @@ export function register( config: ActionsConfig ): typeof STORE_KEY { throw new Error( 'Could not get all blog access.' ); } ); - registerStore< State >( STORE_KEY, { + registerStore( STORE_KEY, { actions: createActions( config ), controls: { ...controls, ...dataControls, ...wpcomRequestControls, - } as any, + }, reducer, selectors, } ); } return STORE_KEY; } - -declare module '@wordpress/data' { - function dispatch( key: typeof STORE_KEY ): DispatchFromMap< ReturnType< typeof createActions > >; - function select( key: typeof STORE_KEY ): SelectFromMap< typeof selectors >; -} diff --git a/packages/data-stores/src/automated-transfer-eligibility/index.ts b/packages/data-stores/src/automated-transfer-eligibility/index.ts index 32c10f52aa9cf..6f3316ad6f84b 100644 --- a/packages/data-stores/src/automated-transfer-eligibility/index.ts +++ b/packages/data-stores/src/automated-transfer-eligibility/index.ts @@ -5,7 +5,6 @@ import reducer from './reducer'; import * as resolvers from './resolvers'; import * as selectors from './selectors'; import { State } from './types'; -import type { DispatchFromMap, SelectFromMap } from '../mapped-types'; export * from './types'; export type { State }; @@ -15,19 +14,12 @@ let isRegistered = false; export function register(): typeof STORE_KEY { if ( ! isRegistered ) { isRegistered = true; - registerStore< State >( STORE_KEY, { + registerStore( STORE_KEY, { actions, reducer, resolvers, - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore Until createRegistrySelector is typed correctly selectors, } ); } return STORE_KEY; } - -declare module '@wordpress/data' { - function dispatch( key: typeof STORE_KEY ): DispatchFromMap< typeof actions >; - function select( key: typeof STORE_KEY ): SelectFromMap< typeof selectors >; -} diff --git a/packages/data-stores/src/automated-transfer-eligibility/selectors.ts b/packages/data-stores/src/automated-transfer-eligibility/selectors.ts index 147a0b57829d1..38f3b118627ff 100644 --- a/packages/data-stores/src/automated-transfer-eligibility/selectors.ts +++ b/packages/data-stores/src/automated-transfer-eligibility/selectors.ts @@ -5,6 +5,7 @@ import { TransferEligibilityWarning, TransferEligibilityError, TransferEligibility, + TransferSelectFn, } from './types'; export const getAutomatedTransferEligibility = ( @@ -18,7 +19,7 @@ export const getAutomatedTransferEligibility = ( }; export const getEligibilityHolds = createRegistrySelector( - ( select ) => + ( select: TransferSelectFn ) => ( state: State, siteId: number | null ): TransferEligibilityError[] | null => { const transferEligibility = select( STORE_KEY ).getAutomatedTransferEligibility( siteId ); @@ -39,7 +40,7 @@ export const getEligibilityHolds = createRegistrySelector( ); export const getEligibilityWarnings = createRegistrySelector( - ( select ) => + ( select: TransferSelectFn ) => ( state: State, siteId: number | null ): TransferEligibilityWarning[] | null => { const transferEligibility = select( STORE_KEY ).getAutomatedTransferEligibility( siteId ); @@ -66,10 +67,8 @@ export const getEligibilityWarnings = createRegistrySelector( ); export const getNonSubdomainWarnings = createRegistrySelector( - ( select ) => + ( select: TransferSelectFn ) => ( state: State, siteId: number | null ): TransferEligibilityWarning[] | null => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore Until createRegistrySelector is typed correctly const eligibilityWarnings = select( STORE_KEY ).getEligibilityWarnings( siteId ); if ( ! eligibilityWarnings ) { @@ -83,10 +82,8 @@ export const getNonSubdomainWarnings = createRegistrySelector( ); export const getWpcomSubdomainWarning = createRegistrySelector( - ( select ) => + ( select: TransferSelectFn ) => ( state: State, siteId: number | null ): TransferEligibilityWarning | null => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore Until createRegistrySelector is typed correctly const eligibilityWarnings = select( STORE_KEY ).getEligibilityWarnings( siteId ); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore Until createRegistrySelector is typed correctly diff --git a/packages/data-stores/src/automated-transfer-eligibility/types.ts b/packages/data-stores/src/automated-transfer-eligibility/types.ts index 74db5e5016ac6..b161df58e48a3 100644 --- a/packages/data-stores/src/automated-transfer-eligibility/types.ts +++ b/packages/data-stores/src/automated-transfer-eligibility/types.ts @@ -1,5 +1,6 @@ import * as actions from './actions'; -import type { DispatchFromMap } from '../mapped-types'; +import * as selectors from './selectors'; +import type { DispatchFromMap, SelectFromMap } from '../mapped-types'; export interface Dispatch { dispatch: DispatchFromMap< typeof actions >; @@ -40,3 +41,5 @@ export type State = { export interface StatusMapping { [ key: string ]: any; } + +export type TransferSelectFn = ( storeKey: string ) => SelectFromMap< typeof selectors >; diff --git a/packages/data-stores/src/domain-suggestions/index.ts b/packages/data-stores/src/domain-suggestions/index.ts index b77d0dfb5ad2f..2db77931434af 100644 --- a/packages/data-stores/src/domain-suggestions/index.ts +++ b/packages/data-stores/src/domain-suggestions/index.ts @@ -5,7 +5,6 @@ import { STORE_KEY } from './constants'; import reducer, { State } from './reducer'; import * as resolvers from './resolvers'; import * as selectors from './selectors'; -import type { DispatchFromMap, SelectFromMap } from '../mapped-types'; export * from './types'; export * from './constants'; @@ -17,18 +16,13 @@ let isRegistered = false; export function register(): typeof STORE_KEY { if ( ! isRegistered ) { isRegistered = true; - registerStore< State >( STORE_KEY, { + registerStore( STORE_KEY, { actions, - controls: controls as any, - reducer: reducer as any, + controls, + reducer, resolvers, selectors, } ); } return STORE_KEY; } - -declare module '@wordpress/data' { - function dispatch( key: typeof STORE_KEY ): DispatchFromMap< typeof actions >; - function select( key: typeof STORE_KEY ): SelectFromMap< typeof selectors >; -} diff --git a/packages/data-stores/src/domain-suggestions/types.ts b/packages/data-stores/src/domain-suggestions/types.ts index c6b0c0b9a9099..b3c9b21aaf80a 100644 --- a/packages/data-stores/src/domain-suggestions/types.ts +++ b/packages/data-stores/src/domain-suggestions/types.ts @@ -1,4 +1,6 @@ +import * as selectors from './selectors'; import type { DataStatus } from './constants'; +import type { SelectFromMap } from '../mapped-types'; export interface DomainSuggestionQuery { /** @@ -257,3 +259,5 @@ export interface DomainSuggestionState { export type DomainAvailabilities = Record< string, DomainAvailability | undefined >; export type DomainSuggestionSelectorOptions = Partial< Exclude< DomainSuggestionQuery, 'query' > >; + +export type DomainSuggestionsSelect = SelectFromMap< typeof selectors >; diff --git a/packages/data-stores/src/help-center/index.ts b/packages/data-stores/src/help-center/index.ts index 60eeacdcd4231..85017359e7388 100644 --- a/packages/data-stores/src/help-center/index.ts +++ b/packages/data-stores/src/help-center/index.ts @@ -7,7 +7,6 @@ import { STORE_KEY } from './constants'; import reducer, { State } from './reducer'; import * as selectors from './selectors'; export type { State }; -import type { SelectFromMap, DispatchFromMap } from '../mapped-types'; let isRegistered = false; @@ -15,10 +14,10 @@ export function register(): typeof STORE_KEY { use( plugins.persistence, persistOptions ); if ( ! isRegistered ) { - registerStore< State >( STORE_KEY, { + registerStore( STORE_KEY, { actions, - reducer: reducer as any, // eslint-disable-line @typescript-eslint/no-explicit-any - controls: { ...controls, ...wpcomRequestControls } as any, + reducer, + controls: { ...controls, ...wpcomRequestControls }, selectors, persist: [ 'site', 'message', 'userDeclaredSite', 'userDeclaredSiteUrl', 'subject' ], } ); @@ -28,9 +27,4 @@ export function register(): typeof STORE_KEY { return STORE_KEY; } -declare module '@wordpress/data' { - function dispatch( key: typeof STORE_KEY ): DispatchFromMap< typeof actions >; - function select( key: typeof STORE_KEY ): SelectFromMap< typeof selectors >; -} - export type { HelpCenterSite } from './types'; diff --git a/packages/data-stores/src/help-center/types.ts b/packages/data-stores/src/help-center/types.ts index 375dd04f7f300..efbd69462291e 100644 --- a/packages/data-stores/src/help-center/types.ts +++ b/packages/data-stores/src/help-center/types.ts @@ -1,5 +1,6 @@ import * as actions from './actions'; -import type { DispatchFromMap } from '../mapped-types'; +import * as selectors from './selectors'; +import type { DispatchFromMap, SelectFromMap } from '../mapped-types'; export type Location = { pathname: string; @@ -37,3 +38,5 @@ export interface APIFetchOptions { global: boolean; path: string; } + +export type HelpCenterSelect = SelectFromMap< typeof selectors >; diff --git a/packages/data-stores/src/i18n/index.ts b/packages/data-stores/src/i18n/index.ts index 19be0fb41a2eb..a99303c0caeeb 100644 --- a/packages/data-stores/src/i18n/index.ts +++ b/packages/data-stores/src/i18n/index.ts @@ -5,7 +5,6 @@ import { STORE_KEY } from './constants'; import reducer, { State } from './reducer'; import * as resolvers from './resolvers'; import * as selectors from './selectors'; -import type { SelectFromMap, DispatchFromMap } from '../mapped-types'; export type { State }; export type { LocalizedLanguageNames } from './types'; @@ -15,18 +14,13 @@ let isRegistered = false; export function register(): typeof STORE_KEY { if ( ! isRegistered ) { isRegistered = true; - registerStore< State >( STORE_KEY, { + registerStore( STORE_KEY, { resolvers, actions, controls, - reducer: reducer as any, + reducer, selectors, } ); } return STORE_KEY; } - -declare module '@wordpress/data' { - function dispatch( key: typeof STORE_KEY ): DispatchFromMap< typeof actions >; - function select( key: typeof STORE_KEY ): SelectFromMap< typeof selectors >; -} diff --git a/packages/data-stores/src/i18n/types.ts b/packages/data-stores/src/i18n/types.ts index 384e5f34e8cd6..4b372c7d6ad89 100644 --- a/packages/data-stores/src/i18n/types.ts +++ b/packages/data-stores/src/i18n/types.ts @@ -1,3 +1,7 @@ +import * as selectors from './selectors'; +import type { SelectFromMap } from '../mapped-types'; +export type I18nSelect = SelectFromMap< typeof selectors >; + export type LocalizedLanguageNames = { [ languageSlug: string ]: { name: string; en: string; localized: string }; }; diff --git a/packages/data-stores/src/index.ts b/packages/data-stores/src/index.ts index 37f01d259b364..aade73be2535f 100644 --- a/packages/data-stores/src/index.ts +++ b/packages/data-stores/src/index.ts @@ -32,6 +32,9 @@ export * from './templates'; export * from './onboard/types'; export * from './domain-suggestions/types'; export * from './plans/types'; +export * from './subscriber/types'; +export * from './launch/types'; +export * from './user/types'; export { Analyzer, @@ -62,4 +65,11 @@ export { getContextResults } from './contextual-help/contextual-help'; export { generateAdminSections } from './contextual-help/admin-sections'; export type { LinksForSection } from './contextual-help/contextual-help'; export * from './contextual-help/constants'; -export type { HelpCenterSite } from './help-center/types'; +export type { AnalyzerSelect } from './analyzer/types'; +export type { I18nSelect } from './i18n/types'; +export type { HelpCenterSite, HelpCenterSelect } from './help-center/types'; +export type { ProductsListSelect } from './products-list/types'; +export type { OnboardSelect } from './onboard'; +export type { StepperInternalSelect } from './stepper-internal'; +export type { WpcomFeaturesSelect } from './wpcom-features/types'; +export type { WpcomPlansUISelect } from './wpcom-plans-ui/types'; diff --git a/packages/data-stores/src/launch/index.ts b/packages/data-stores/src/launch/index.ts index 1086c37cb74bb..b9139828b091b 100644 --- a/packages/data-stores/src/launch/index.ts +++ b/packages/data-stores/src/launch/index.ts @@ -5,7 +5,6 @@ import * as actions from './actions'; import { STORE_KEY } from './constants'; import reducer, { State } from './reducer'; import * as selectors from './selectors'; -import type { SelectFromMap, DispatchFromMap } from '../mapped-types'; export type { State }; export type { LaunchStepType } from './types'; @@ -18,7 +17,7 @@ let isRegistered = false; export function register(): typeof STORE_KEY { if ( ! isRegistered ) { isRegistered = true; - registerStore< State >( STORE_KEY, { + registerStore( STORE_KEY, { actions, controls, reducer, @@ -37,8 +36,3 @@ export function register(): typeof STORE_KEY { } return STORE_KEY; } - -declare module '@wordpress/data' { - function dispatch( key: typeof STORE_KEY ): DispatchFromMap< typeof actions >; - function select( key: typeof STORE_KEY ): SelectFromMap< typeof selectors >; -} diff --git a/packages/data-stores/src/launch/types.ts b/packages/data-stores/src/launch/types.ts index f0b33e0e2ff7c..661863b9d7d71 100644 --- a/packages/data-stores/src/launch/types.ts +++ b/packages/data-stores/src/launch/types.ts @@ -1,4 +1,8 @@ +import * as selectors from './selectors'; import type { LaunchStep } from './data'; +import type { SelectFromMap } from '../mapped-types'; import type { ValuesType } from 'utility-types'; export type LaunchStepType = ValuesType< typeof LaunchStep >; + +export type LaunchSelect = SelectFromMap< typeof selectors >; diff --git a/packages/data-stores/src/onboard/index.ts b/packages/data-stores/src/onboard/index.ts index 9462c2f17aaf9..81f743f607d78 100644 --- a/packages/data-stores/src/onboard/index.ts +++ b/packages/data-stores/src/onboard/index.ts @@ -5,9 +5,10 @@ import * as actions from './actions'; import { STORE_KEY } from './constants'; import reducer, { State } from './reducer'; import * as selectors from './selectors'; -import type { SelectFromMap, DispatchFromMap } from '../mapped-types'; +import type { SelectFromMap } from '../mapped-types'; export type { State }; +export type OnboardSelect = SelectFromMap< typeof selectors >; export { SiteGoal, SiteIntent } from './constants'; export * as utils from './utils'; @@ -23,10 +24,10 @@ export function register(): typeof STORE_KEY { } use( plugins.persistence, persistOptions ); - registerStore< State >( STORE_KEY, { + registerStore( STORE_KEY, { actions, controls, - reducer: reducer as any, // eslint-disable-line @typescript-eslint/no-explicit-any + reducer, selectors, persist: [ 'anchorPodcastId', @@ -64,8 +65,3 @@ export function register(): typeof STORE_KEY { isRegistered = true; return STORE_KEY; } - -declare module '@wordpress/data' { - function dispatch( key: typeof STORE_KEY ): DispatchFromMap< typeof actions >; - function select( key: typeof STORE_KEY ): SelectFromMap< typeof selectors >; -} diff --git a/packages/data-stores/src/plans/index.ts b/packages/data-stores/src/plans/index.ts index b47c58285797d..9f75a344da687 100644 --- a/packages/data-stores/src/plans/index.ts +++ b/packages/data-stores/src/plans/index.ts @@ -5,7 +5,6 @@ import { STORE_KEY } from './constants'; import reducer, { State } from './reducer'; import * as resolvers from './resolvers'; import * as selectors from './selectors'; -import type { SelectFromMap, DispatchFromMap } from '../mapped-types'; export type { State }; export type { @@ -39,18 +38,13 @@ let isRegistered = false; export function register(): typeof STORE_KEY { if ( ! isRegistered ) { isRegistered = true; - registerStore< State >( STORE_KEY, { + registerStore( STORE_KEY, { resolvers, actions, - controls: controls as any, + controls, reducer, selectors, } ); } return STORE_KEY; } - -declare module '@wordpress/data' { - function dispatch( key: typeof STORE_KEY ): DispatchFromMap< typeof actions >; - function select( key: typeof STORE_KEY ): SelectFromMap< typeof selectors >; -} diff --git a/packages/data-stores/src/plans/selectors.ts b/packages/data-stores/src/plans/selectors.ts index 7fe22eaf338f3..b84522b199c8c 100644 --- a/packages/data-stores/src/plans/selectors.ts +++ b/packages/data-stores/src/plans/selectors.ts @@ -15,6 +15,7 @@ import type { PlanProduct, PlanPath, PlanSlug, + PlansSelect, StorePlanSlug, } from './types'; @@ -37,9 +38,9 @@ export const getPlanByProductId = ( return undefined; } - return select( STORE_KEY ) + return ( select( STORE_KEY ) as PlansSelect ) .getSupportedPlans( locale ) - .find( ( plan ) => plan.productIds.indexOf( productId ) > -1 ); + .find( ( plan: Plan ) => plan.productIds.indexOf( productId ) > -1 ); }; export const getPlanProductById = ( @@ -50,9 +51,9 @@ export const getPlanProductById = ( return undefined; } - return select( STORE_KEY ) + return ( select( STORE_KEY ) as PlansSelect ) .getPlansProducts() - .find( ( product ) => product.productId === productId ); + .find( ( product: PlanProduct ) => product.productId === productId ); }; export const getPlanByPeriodAgnosticSlug = ( @@ -63,21 +64,21 @@ export const getPlanByPeriodAgnosticSlug = ( if ( ! slug ) { return undefined; } - return select( STORE_KEY ) + return ( select( STORE_KEY ) as PlansSelect ) .getSupportedPlans( locale ) - .find( ( plan ) => plan.periodAgnosticSlug === slug ); + .find( ( plan: Plan ) => plan.periodAgnosticSlug === slug ); }; export const getDefaultPaidPlan = ( _: State, locale: string ): Plan | undefined => { - return select( STORE_KEY ) + return ( select( STORE_KEY ) as PlansSelect ) .getSupportedPlans( locale ) - .find( ( plan ) => plan.periodAgnosticSlug === DEFAULT_PAID_PLAN ); + .find( ( plan: Plan ) => plan.periodAgnosticSlug === DEFAULT_PAID_PLAN ); }; export const getDefaultFreePlan = ( _: State, locale: string ): Plan | undefined => { - return select( STORE_KEY ) + return ( select( STORE_KEY ) as PlansSelect ) .getSupportedPlans( locale ) - .find( ( plan ) => plan.periodAgnosticSlug === TIMELESS_PLAN_FREE ); + .find( ( plan: Plan ) => plan.periodAgnosticSlug === TIMELESS_PLAN_FREE ); }; export const getSupportedPlans = ( state: State, _locale: string ): Plan[] => { @@ -97,9 +98,9 @@ export const getPrices = ( _state: State, _locale: string ): Record< StorePlanSl deprecate( 'getPrices', { alternative: 'getPlanProduct().price', } ); - return select( STORE_KEY ) + return ( select( STORE_KEY ) as PlansSelect ) .getPlansProducts() - .reduce( ( prices, plan ) => { + .reduce( ( prices: Record< StorePlanSlug, string >, plan: PlanProduct ) => { prices[ plan.storeSlug ] = plan.price; return prices; }, {} as Record< StorePlanSlug, string > ); @@ -114,17 +115,17 @@ export const getPlanByPath = ( return undefined; } - const planProduct = select( STORE_KEY ) + const planProduct = ( select( STORE_KEY ) as PlansSelect ) .getPlansProducts() - .find( ( product ) => product.pathSlug === path ); + .find( ( product: PlanProduct ) => product.pathSlug === path ); if ( ! planProduct ) { return undefined; } - return select( STORE_KEY ) + return ( select( STORE_KEY ) as PlansSelect ) .getSupportedPlans( locale ) - .find( ( plan ) => plan.periodAgnosticSlug === planProduct.periodAgnosticSlug ); + .find( ( plan: Plan ) => plan.periodAgnosticSlug === planProduct.periodAgnosticSlug ); }; export const getPlanProduct = ( @@ -136,9 +137,9 @@ export const getPlanProduct = ( return undefined; } - return select( STORE_KEY ) + return ( select( STORE_KEY ) as PlansSelect ) .getPlansProducts() - .find( ( product ) => { + .find( ( product: PlanProduct ) => { const matchesSlug = product.periodAgnosticSlug === periodAgnosticSlug; // The billing period doesn't matter when dealing with free plan const matchesBillingPeriod = diff --git a/packages/data-stores/src/plans/types.ts b/packages/data-stores/src/plans/types.ts index 5219b0e81248e..29111ed460f49 100644 --- a/packages/data-stores/src/plans/types.ts +++ b/packages/data-stores/src/plans/types.ts @@ -1,4 +1,6 @@ +import * as selectors from './selectors'; import type { plansProductSlugs, plansSlugs } from './constants'; +import type { SelectFromMap } from '../mapped-types'; export type StorePlanSlug = typeof plansProductSlugs[ number ]; export type PlanSlug = typeof plansSlugs[ number ]; @@ -121,3 +123,5 @@ export interface DetailsAPIResponse { features_by_type: FeaturesByType[]; features: DetailsAPIFeature[]; } + +export type PlansSelect = SelectFromMap< typeof selectors >; diff --git a/packages/data-stores/src/products-list/index.ts b/packages/data-stores/src/products-list/index.ts index e0a0af7ba5a8d..6b7040f4db661 100644 --- a/packages/data-stores/src/products-list/index.ts +++ b/packages/data-stores/src/products-list/index.ts @@ -5,7 +5,6 @@ import { STORE_KEY } from './constants'; import reducer, { State } from './reducer'; import * as resolvers from './resolvers'; import * as selectors from './selectors'; -import type { DispatchFromMap, SelectFromMap } from '../mapped-types'; export * from './types'; export type { State }; @@ -15,18 +14,13 @@ let isRegistered = false; export function register(): typeof STORE_KEY { if ( ! isRegistered ) { isRegistered = true; - registerStore< State >( STORE_KEY, { + registerStore( STORE_KEY, { actions, - controls: controls as any, // eslint-disable-line @typescript-eslint/no-explicit-any - reducer: reducer as any, // eslint-disable-line @typescript-eslint/no-explicit-any + controls, + reducer, resolvers, selectors, } ); } return STORE_KEY; } - -declare module '@wordpress/data' { - function dispatch( key: typeof STORE_KEY ): DispatchFromMap< typeof actions >; - function select( key: typeof STORE_KEY ): SelectFromMap< typeof selectors >; -} diff --git a/packages/data-stores/src/products-list/types.ts b/packages/data-stores/src/products-list/types.ts index eabd145ae0ed3..d94458829ea7a 100644 --- a/packages/data-stores/src/products-list/types.ts +++ b/packages/data-stores/src/products-list/types.ts @@ -1,5 +1,8 @@ import * as actions from './actions'; -import type { DispatchFromMap } from '../mapped-types'; +import * as selectors from './selectors'; +import type { DispatchFromMap, SelectFromMap } from '../mapped-types'; + +export type ProductsListSelect = SelectFromMap< typeof selectors >; export interface Dispatch { dispatch: DispatchFromMap< typeof actions >; diff --git a/packages/data-stores/src/reader/index.ts b/packages/data-stores/src/reader/index.ts index 4636eb8e66ba7..1ac64423f4359 100644 --- a/packages/data-stores/src/reader/index.ts +++ b/packages/data-stores/src/reader/index.ts @@ -6,7 +6,6 @@ import { STORE_KEY } from './constants'; import reducer, { State } from './reducer'; import * as resolvers from './resolvers'; import * as selectors from './selectors'; -import type { SelectFromMap, DispatchFromMap } from '../mapped-types'; export type { State }; export { STORE_KEY }; @@ -18,10 +17,10 @@ let isRegistered = false; export function register(): typeof STORE_KEY { if ( ! isRegistered ) { isRegistered = true; - registerStore< State >( STORE_KEY, { + registerStore( STORE_KEY, { actions, - controls: controls as any, - reducer: reducer as any, + controls, + reducer, resolvers, selectors, persist: [ 'teams' ], @@ -29,8 +28,3 @@ export function register(): typeof STORE_KEY { } return STORE_KEY; } - -declare module '@wordpress/data' { - function dispatch( key: typeof STORE_KEY ): DispatchFromMap< typeof actions >; - function select( key: typeof STORE_KEY ): SelectFromMap< typeof selectors >; -} diff --git a/packages/data-stores/src/site/index.ts b/packages/data-stores/src/site/index.ts index 040fed1b801fb..e024e2fe6589a 100644 --- a/packages/data-stores/src/site/index.ts +++ b/packages/data-stores/src/site/index.ts @@ -6,7 +6,6 @@ import { STORE_KEY } from './constants'; import reducer, { State } from './reducer'; import * as resolvers from './resolvers'; import * as selectors from './selectors'; -import type { DispatchFromMap, SelectFromMap } from '../mapped-types'; import type { WpcomClientCredentials } from '../shared-types'; export * from './types'; @@ -19,10 +18,9 @@ export function register( clientCreds: WpcomClientCredentials ): typeof STORE_KE use( plugins.persistence, persistOptions ); isRegistered = true; - registerStore< State >( STORE_KEY, { + registerStore( STORE_KEY, { actions: createActions( clientCreds ), - // eslint-disable-next-line @typescript-eslint/no-explicit-any - controls: controls as any, + controls, reducer, resolvers, selectors, @@ -31,8 +29,3 @@ export function register( clientCreds: WpcomClientCredentials ): typeof STORE_KE } return STORE_KEY; } - -declare module '@wordpress/data' { - function dispatch( key: typeof STORE_KEY ): DispatchFromMap< ReturnType< typeof createActions > >; - function select( key: typeof STORE_KEY ): SelectFromMap< typeof selectors >; -} diff --git a/packages/data-stores/src/site/selectors.ts b/packages/data-stores/src/site/selectors.ts index 65d789d9ed94a..f940c8a9ad122 100644 --- a/packages/data-stores/src/site/selectors.ts +++ b/packages/data-stores/src/site/selectors.ts @@ -1,6 +1,6 @@ import { select } from '@wordpress/data'; import { STORE_KEY } from './constants'; -import { SiteLaunchStatus, SiteOption } from './types'; +import { Domain, SiteLaunchStatus, SiteDetails, SiteOption, SiteSelect } from './types'; import type { State } from './reducer'; export const getState = ( state: State ) => state; @@ -19,7 +19,10 @@ export const isNewSite = ( state: State ) => !! state.newSite.data; * @param state {State} state object * @param siteId {number} id of the site to look up */ -export const getSite = ( state: State, siteId: number | string ) => { +export const getSite: ( state: State, siteId: number | string ) => SiteDetails | undefined = ( + state, + siteId +) => { return ( // Try matching numeric site ID state.sites[ siteId ] || @@ -33,15 +36,17 @@ export const getSite = ( state: State, siteId: number | string ) => { ); }; -export const getSiteIdBySlug = ( _: State, slug: string ) => { - return select( STORE_KEY ).getSite( slug )?.ID; +export const getSiteIdBySlug: ( _: State, slug: string ) => number | undefined = ( _, slug ) => { + return ( select( STORE_KEY ) as SiteSelect ).getSite( slug )?.ID; }; -export const getSiteTitle = ( _: State, siteId: number ) => - select( STORE_KEY ).getSite( siteId )?.name; +export const getSiteTitle: ( _: State, siteId: number ) => string | undefined = ( _, siteId ) => + ( select( STORE_KEY ) as SiteSelect ).getSite( siteId )?.name; -export const getSiteVerticalId = ( _: State, siteId: number ) => - select( STORE_KEY ).getSite( siteId )?.options?.site_vertical_id; +export const getSiteVerticalId: ( _: State, siteId: number ) => string | null | undefined = ( + _, + siteId +) => ( select( STORE_KEY ) as SiteSelect ).getSite( siteId )?.options?.site_vertical_id; // @TODO: Return LaunchStatus instead of a boolean export const isSiteLaunched = ( state: State, siteId: number ) => { @@ -53,12 +58,17 @@ export const isSiteLaunching = ( state: State, siteId: number ) => { return state.launchStatus[ siteId ]?.status === SiteLaunchStatus.IN_PROGRESS; }; -export const isSiteAtomic = ( state: State, siteId: number | string ) => { - return select( STORE_KEY ).getSite( siteId )?.options?.is_wpcom_atomic === true; +export const isSiteAtomic: ( _: State, siteId: number | string ) => boolean = ( state, siteId ) => { + return ( select( STORE_KEY ) as SiteSelect ).getSite( siteId )?.options?.is_wpcom_atomic === true; }; -export const isSiteWPForTeams = ( state: State, siteId: number | string ) => { - return select( STORE_KEY ).getSite( siteId )?.options?.is_wpforteams_site === true; +export const isSiteWPForTeams: ( _: State, siteId: number | string ) => boolean = ( + state, + siteId +) => { + return ( + ( select( STORE_KEY ) as SiteSelect ).getSite( siteId )?.options?.is_wpforteams_site === true + ); }; export const getSiteDomains = ( state: State, siteId: number ) => { @@ -89,15 +99,18 @@ export const getSiteOption = ( state: State, siteId: number, optionName: SiteOpt return state.sites[ siteId ]?.options?.[ optionName ]; }; -export const getPrimarySiteDomain = ( _: State, siteId: number ) => - select( STORE_KEY ) +export const getPrimarySiteDomain: ( _: State, siteId: number ) => Domain | undefined = ( + _, + siteId +) => + ( select( STORE_KEY ) as SiteSelect ) .getSiteDomains( siteId ) - ?.find( ( domain ) => domain.primary_domain ); + ?.find( ( domain: Domain ) => domain.primary_domain ); -export const getSiteSubdomain = ( _: State, siteId: number ) => - select( STORE_KEY ) +export const getSiteSubdomain: ( _: State, siteId: number ) => Domain | undefined = ( _, siteId ) => + ( select( STORE_KEY ) as SiteSelect ) .getSiteDomains( siteId ) - ?.find( ( domain ) => domain.is_subdomain ); + ?.find( ( domain: Domain ) => domain.is_subdomain ); export const getSiteLatestAtomicTransfer = ( state: State, siteId: number ) => { return state.latestAtomicTransferStatus[ siteId ]?.transfer; @@ -129,16 +142,23 @@ export const siteHasFeature = ( featureKey: string ): boolean => { return Boolean( - siteId && select( STORE_KEY ).getSite( siteId )?.plan?.features.active.includes( featureKey ) + siteId && + ( select( STORE_KEY ) as SiteSelect ) + .getSite( siteId ) + ?.plan?.features.active.includes( featureKey ) ); }; -export const requiresUpgrade = ( state: State, siteId: number | null ) => { - return siteId && ! select( STORE_KEY ).siteHasFeature( siteId, 'woop' ); +// TODO: The `0` here seems wrong and should likely be addressed. +export const requiresUpgrade: ( state: State, siteId: number | null ) => boolean | 0 | null = ( + state, + siteId +) => { + return siteId && ! ( select( STORE_KEY ) as SiteSelect ).siteHasFeature( siteId, 'woop' ); }; export function isJetpackSite( state: State, siteId?: number ): boolean { - return Boolean( siteId && select( STORE_KEY ).getSite( siteId )?.jetpack ); + return Boolean( siteId && ( select( STORE_KEY ) as SiteSelect ).getSite( siteId )?.jetpack ); } export function isEligibleForProPlan( state: State, siteId?: number ): boolean { diff --git a/packages/data-stores/src/site/types.ts b/packages/data-stores/src/site/types.ts index eaeb0c9eb1476..9c2c0fef8d446 100644 --- a/packages/data-stores/src/site/types.ts +++ b/packages/data-stores/src/site/types.ts @@ -1,5 +1,6 @@ +import * as selectors from './selectors'; import type { ActionCreators } from './actions'; -import type { DispatchFromMap } from '../mapped-types'; +import type { DispatchFromMap, SelectFromMap } from '../mapped-types'; import type { FeatureId } from '../wpcom-features'; export interface Dispatch { @@ -489,6 +490,8 @@ export interface CurrentTheme { id: string; } +export type SiteSelect = SelectFromMap< typeof selectors >; + export interface SourceSiteMigrationDetails { status: string; target_blog_id?: number; diff --git a/packages/data-stores/src/stepper-internal/index.ts b/packages/data-stores/src/stepper-internal/index.ts index 10e59e4b2a01d..17c1ca3998443 100644 --- a/packages/data-stores/src/stepper-internal/index.ts +++ b/packages/data-stores/src/stepper-internal/index.ts @@ -5,25 +5,21 @@ import * as actions from './actions'; import { STORE_KEY } from './constants'; import reducer, { State } from './reducer'; import * as selectors from './selectors'; -import type { SelectFromMap, DispatchFromMap } from '../mapped-types'; +import type { SelectFromMap } from '../mapped-types'; export type { State }; +export type StepperInternalSelect = SelectFromMap< typeof selectors >; export function register(): typeof STORE_KEY { use( plugins.persistence, persistOptions ); - registerStore< State >( STORE_KEY, { + registerStore( STORE_KEY, { actions, controls, - reducer: reducer as any, // eslint-disable-line @typescript-eslint/no-explicit-any + reducer, selectors, persist: [ 'stepData' ], } ); return STORE_KEY; } - -declare module '@wordpress/data' { - function dispatch( key: typeof STORE_KEY ): DispatchFromMap< typeof actions >; - function select( key: typeof STORE_KEY ): SelectFromMap< typeof selectors >; -} diff --git a/packages/data-stores/src/subscriber/index.ts b/packages/data-stores/src/subscriber/index.ts index 0f61793e75f40..8366741fa76b9 100644 --- a/packages/data-stores/src/subscriber/index.ts +++ b/packages/data-stores/src/subscriber/index.ts @@ -5,24 +5,18 @@ import { STORE_KEY } from './constants'; import reducer, { State } from './reducers'; import * as selectors from './selectors'; export * from './types'; -import type { DispatchFromMap, SelectFromMap } from '../mapped-types'; export type { State }; let isRegistered = false; export function register(): typeof STORE_KEY { if ( ! isRegistered ) { isRegistered = true; - registerStore< State >( STORE_KEY, { + registerStore( STORE_KEY, { actions: createActions(), - controls: controls as any, - reducer: reducer as any, + controls, + reducer, selectors, } ); } return STORE_KEY; } - -declare module '@wordpress/data' { - function dispatch( key: typeof STORE_KEY ): DispatchFromMap< ReturnType< typeof createActions > >; - function select( key: typeof STORE_KEY ): SelectFromMap< typeof selectors >; -} diff --git a/packages/data-stores/src/subscriber/types.ts b/packages/data-stores/src/subscriber/types.ts index 07d48c0624769..ed6d70d7cbaaf 100644 --- a/packages/data-stores/src/subscriber/types.ts +++ b/packages/data-stores/src/subscriber/types.ts @@ -1,5 +1,6 @@ import * as actions from './actions'; -import type { DispatchFromMap } from '../mapped-types'; +import * as selectors from './selectors'; +import type { DispatchFromMap, SelectFromMap } from '../mapped-types'; export interface SubscriberState { add?: { @@ -48,6 +49,8 @@ export type ImportSubscribersResponse = { export type GetSubscribersImportResponse = ImportJob; export type GetSubscribersImportsResponse = ImportJob[]; -export interface Dispatch { +export interface SubscriberDispatch { dispatch: DispatchFromMap< typeof actions >; } + +export type SubscriberSelect = SelectFromMap< typeof selectors >; diff --git a/packages/data-stores/src/user/index.ts b/packages/data-stores/src/user/index.ts index 2d6e427d52ef3..342033abc1c52 100644 --- a/packages/data-stores/src/user/index.ts +++ b/packages/data-stores/src/user/index.ts @@ -5,7 +5,6 @@ import { STORE_KEY } from './constants'; import reducer, { State } from './reducer'; import { createResolvers } from './resolvers'; import * as selectors from './selectors'; -import type { DispatchFromMap, SelectFromMap } from '../mapped-types'; import type { WpcomClientCredentials } from '../shared-types'; export * from './types'; @@ -15,9 +14,9 @@ let isRegistered = false; export function register( clientCreds: WpcomClientCredentials ): typeof STORE_KEY { if ( ! isRegistered ) { isRegistered = true; - registerStore< State >( STORE_KEY, { + registerStore( STORE_KEY, { actions: createActions( clientCreds ), - controls: controls as any, + controls, reducer, resolvers: createResolvers( clientCreds ), selectors, @@ -25,8 +24,3 @@ export function register( clientCreds: WpcomClientCredentials ): typeof STORE_KE } return STORE_KEY; } - -declare module '@wordpress/data' { - function dispatch( key: typeof STORE_KEY ): DispatchFromMap< ReturnType< typeof createActions > >; - function select( key: typeof STORE_KEY ): SelectFromMap< typeof selectors >; -} diff --git a/packages/data-stores/src/user/types.ts b/packages/data-stores/src/user/types.ts index a4a9837d809d1..344327b568b7d 100644 --- a/packages/data-stores/src/user/types.ts +++ b/packages/data-stores/src/user/types.ts @@ -1,3 +1,5 @@ +import * as selectors from './selectors'; +import type { SelectFromMap } from '../mapped-types'; import type { Action } from 'redux'; export interface CurrentUser { @@ -77,3 +79,5 @@ export interface CreateAccountParams { export interface CreateAccountAction extends Action { params?: CreateAccountParams; } + +export type UserSelect = SelectFromMap< typeof selectors >; diff --git a/packages/data-stores/src/wpcom-features/index.ts b/packages/data-stores/src/wpcom-features/index.ts index f5bf522cc2bee..fe2ad47cb9b04 100644 --- a/packages/data-stores/src/wpcom-features/index.ts +++ b/packages/data-stores/src/wpcom-features/index.ts @@ -3,7 +3,6 @@ import { controls } from '@wordpress/data-controls'; import { STORE_KEY } from './constants'; import reducer, { State } from './reducer'; import * as selectors from './selectors'; -import type { SelectFromMap } from '../mapped-types'; import type { Reducer, AnyAction } from 'redux'; export type { State }; @@ -16,7 +15,7 @@ let isRegistered = false; export function register(): typeof STORE_KEY { if ( ! isRegistered ) { isRegistered = true; - registerStore< State >( STORE_KEY, { + registerStore( STORE_KEY, { controls, reducer: reducer as Reducer< State, AnyAction >, selectors, @@ -24,7 +23,3 @@ export function register(): typeof STORE_KEY { } return STORE_KEY; } - -declare module '@wordpress/data' { - function select( key: typeof STORE_KEY ): SelectFromMap< typeof selectors >; -} diff --git a/packages/data-stores/src/wpcom-features/types.ts b/packages/data-stores/src/wpcom-features/types.ts index 603b2f0df4c79..3b6a484b4b2a1 100644 --- a/packages/data-stores/src/wpcom-features/types.ts +++ b/packages/data-stores/src/wpcom-features/types.ts @@ -1,3 +1,5 @@ +import * as selectors from './selectors'; +import type { SelectFromMap } from '../mapped-types'; import type { PlanSlug } from '../plans'; export type FeatureId = @@ -14,3 +16,5 @@ export interface Feature { id: FeatureId; minSupportedPlan: PlanSlug; } + +export type WpcomFeaturesSelect = SelectFromMap< typeof selectors >; diff --git a/packages/data-stores/src/wpcom-plans-ui/index.ts b/packages/data-stores/src/wpcom-plans-ui/index.ts index 95e2d8c81613d..e8963c81d6225 100644 --- a/packages/data-stores/src/wpcom-plans-ui/index.ts +++ b/packages/data-stores/src/wpcom-plans-ui/index.ts @@ -4,7 +4,6 @@ import * as actions from './actions'; import { STORE_KEY } from './constants'; import reducer, { State } from './reducer'; import * as selectors from './selectors'; -import type { SelectFromMap, DispatchFromMap } from '../mapped-types'; import type { WpcomPlansUIAction } from './actions'; import type { Reducer } from 'redux'; @@ -15,7 +14,7 @@ let isRegistered = false; export function register(): typeof STORE_KEY { if ( ! isRegistered ) { isRegistered = true; - registerStore< State >( STORE_KEY, { + registerStore( STORE_KEY, { actions, controls, reducer: reducer as Reducer< State, WpcomPlansUIAction >, @@ -24,8 +23,3 @@ export function register(): typeof STORE_KEY { } return STORE_KEY; } - -declare module '@wordpress/data' { - function dispatch( key: typeof STORE_KEY ): DispatchFromMap< typeof actions >; - function select( key: typeof STORE_KEY ): SelectFromMap< typeof selectors >; -} diff --git a/packages/data-stores/src/wpcom-plans-ui/types.ts b/packages/data-stores/src/wpcom-plans-ui/types.ts index 62d2afdc70781..cca5b4938615e 100644 --- a/packages/data-stores/src/wpcom-plans-ui/types.ts +++ b/packages/data-stores/src/wpcom-plans-ui/types.ts @@ -1,3 +1,8 @@ +import * as selectors from './selectors'; +import type { SelectFromMap } from '../mapped-types'; + +export type WpcomPlansUISelect = SelectFromMap< typeof selectors >; + export interface DomainUpsellDialog { show: boolean; } diff --git a/packages/design-carousel/package.json b/packages/design-carousel/package.json index 8f7a48f22fc15..f1e9e0226aa45 100644 --- a/packages/design-carousel/package.json +++ b/packages/design-carousel/package.json @@ -49,9 +49,9 @@ "webpack": "^5.68.0" }, "peerDependencies": { - "@wordpress/data": "^6.7.0", - "@wordpress/element": "^4.5.0", - "@wordpress/i18n": "^4.7.0", + "@wordpress/data": "^7.6.0", + "@wordpress/element": "^4.20.0", + "@wordpress/i18n": "^4.22.0", "debug": "^4.3.3", "react": "^17.0.2", "react-dom": "^17.0.2", diff --git a/packages/design-picker/package.json b/packages/design-picker/package.json index dcf1770dfdd9b..e734a15f13adc 100644 --- a/packages/design-picker/package.json +++ b/packages/design-picker/package.json @@ -33,9 +33,9 @@ "@automattic/js-utils": "workspace:^", "@automattic/onboarding": "workspace:^", "@automattic/typography": "workspace:^", - "@wordpress/components": "^19.15.0", - "@wordpress/react-i18n": "^3.7.0", - "@wordpress/url": "^3.10.0", + "@wordpress/components": "^22.1.0", + "@wordpress/react-i18n": "^3.20.0", + "@wordpress/url": "^3.23.0", "classnames": "^2.3.1", "react-query": "^3.32.1", "tslib": "^2.3.0", @@ -57,9 +57,9 @@ "webpack": "^5.68.0" }, "peerDependencies": { - "@wordpress/data": "^6.7.0", - "@wordpress/element": "^4.5.0", - "@wordpress/i18n": "^4.7.0", + "@wordpress/data": "^7.6.0", + "@wordpress/element": "^4.20.0", + "@wordpress/i18n": "^4.22.0", "debug": "^4.3.3", "react": "^17.0.2", "react-dom": "^17.0.2", diff --git a/packages/design-preview/package.json b/packages/design-preview/package.json index 196d6cfa04e04..ae7be22da3829 100644 --- a/packages/design-preview/package.json +++ b/packages/design-preview/package.json @@ -32,11 +32,11 @@ "@automattic/calypso-config": "workspace:^", "@automattic/design-picker": "workspace:^", "@automattic/i18n-utils": "workspace:^", - "@wordpress/block-editor": "^9.1.0", - "@wordpress/components": "^19.15.0", - "@wordpress/compose": "^5.7.0", - "@wordpress/edit-site": "^4.6.0", - "@wordpress/react-i18n": "^3.7.0", + "@wordpress/block-editor": "^10.5.0", + "@wordpress/components": "^22.1.0", + "@wordpress/compose": "^5.20.0", + "@wordpress/edit-site": "^4.19.0", + "@wordpress/react-i18n": "^3.20.0", "classnames": "^2.3.1", "tslib": "^2.3.0" }, @@ -49,9 +49,9 @@ "typescript": "^4.7.4" }, "peerDependencies": { - "@wordpress/data": "^6.7.0", - "@wordpress/element": "^4.5.0", - "@wordpress/i18n": "^4.7.0", + "@wordpress/data": "^7.6.0", + "@wordpress/element": "^4.20.0", + "@wordpress/i18n": "^4.22.0", "debug": "^4.3.3", "react": "^17.0.2", "react-dom": "^17.0.2", diff --git a/packages/domain-picker/package.json b/packages/domain-picker/package.json index 254a46876eec8..ed661c7e0ba44 100644 --- a/packages/domain-picker/package.json +++ b/packages/domain-picker/package.json @@ -35,11 +35,11 @@ "@automattic/i18n-utils": "workspace:^", "@automattic/onboarding": "workspace:^", "@automattic/typography": "workspace:^", - "@wordpress/base-styles": "^4.5.0", - "@wordpress/components": "^19.15.0", - "@wordpress/compose": "^5.7.0", - "@wordpress/icons": "^9.0.0", - "@wordpress/react-i18n": "^3.7.0", + "@wordpress/base-styles": "^4.13.0", + "@wordpress/components": "^22.1.0", + "@wordpress/compose": "^5.20.0", + "@wordpress/icons": "^9.13.0", + "@wordpress/react-i18n": "^3.20.0", "classnames": "^2.3.1", "lodash": "^4.17.21", "tslib": "^2.3.0", @@ -55,9 +55,9 @@ "typescript": "^4.7.4" }, "peerDependencies": { - "@wordpress/data": "^6.7.0", - "@wordpress/element": "^4.5.0", - "@wordpress/i18n": "^4.7.0", + "@wordpress/data": "^7.6.0", + "@wordpress/element": "^4.20.0", + "@wordpress/i18n": "^4.22.0", "react": "^17.0.2", "reakit-utils": "^0.15.1", "redux": "^4.1.2" diff --git a/packages/domain-picker/src/components/domain-categories/index.tsx b/packages/domain-picker/src/components/domain-categories/index.tsx index c22f2c0b05e72..d53d29593281d 100644 --- a/packages/domain-picker/src/components/domain-categories/index.tsx +++ b/packages/domain-picker/src/components/domain-categories/index.tsx @@ -6,6 +6,7 @@ import { useI18n } from '@wordpress/react-i18n'; import classNames from 'classnames'; import * as React from 'react'; import { DOMAIN_SUGGESTIONS_STORE } from '../../constants'; +import type { DomainSuggestionsSelect } from '@automattic/data-stores'; import './style.scss'; @@ -23,8 +24,9 @@ const DomainPickerCategories: React.FunctionComponent< Props > = ( { onSelect, s onSelect( slug ); }; - const domainCategories = useSelect( ( select ) => - select( DOMAIN_SUGGESTIONS_STORE ).getCategories() + const domainCategories = useSelect( + ( select ) => ( select( DOMAIN_SUGGESTIONS_STORE ) as DomainSuggestionsSelect ).getCategories(), + [] ); const allCategoriesLabel = __( 'All Categories', __i18n_text_domain__ ); diff --git a/packages/domain-picker/src/hooks/use-domain-availabilities.ts b/packages/domain-picker/src/hooks/use-domain-availabilities.ts index a2067098e143f..e6e6ae92468b5 100644 --- a/packages/domain-picker/src/hooks/use-domain-availabilities.ts +++ b/packages/domain-picker/src/hooks/use-domain-availabilities.ts @@ -1,8 +1,11 @@ import { useSelect } from '@wordpress/data'; import { DOMAIN_SUGGESTIONS_STORE } from '../constants'; +import type { DomainSuggestionsSelect } from '@automattic/data-stores'; export function useDomainAvailabilities() { return useSelect( ( select ) => { - return select( DOMAIN_SUGGESTIONS_STORE ).getDomainAvailabilities(); + return ( + select( DOMAIN_SUGGESTIONS_STORE ) as DomainSuggestionsSelect + ).getDomainAvailabilities(); }, [] ); } diff --git a/packages/domain-picker/src/hooks/use-domain-suggestions.ts b/packages/domain-picker/src/hooks/use-domain-suggestions.ts index 77b1dc01137b1..de018cfbb1a49 100644 --- a/packages/domain-picker/src/hooks/use-domain-suggestions.ts +++ b/packages/domain-picker/src/hooks/use-domain-suggestions.ts @@ -6,7 +6,10 @@ import { DOMAIN_QUERY_MINIMUM_LENGTH, } from '../constants'; import type { DataStatus } from '@automattic/data-stores/src/domain-suggestions/constants'; -import type { DomainSuggestion } from '@automattic/data-stores/src/domain-suggestions/types'; +import type { + DomainSuggestion, + DomainSuggestionsSelect, +} from '@automattic/data-stores/src/domain-suggestions/types'; type DomainSuggestionsResult = { allDomainSuggestions: DomainSuggestion[] | undefined; @@ -34,8 +37,11 @@ export function useDomainSuggestions( if ( ! domainSearch || domainSearch.length < DOMAIN_QUERY_MINIMUM_LENGTH ) { return; } - const { getDomainSuggestions, getDomainState, getDomainErrorMessage } = - select( DOMAIN_SUGGESTIONS_STORE ); + const { + getDomainSuggestions, + getDomainState, + getDomainErrorMessage, + }: DomainSuggestionsSelect = select( DOMAIN_SUGGESTIONS_STORE ); const retryRequest = (): void => { invalidateResolutionForStoreSelector( '__internalGetDomainSuggestions' ); @@ -57,6 +63,6 @@ export function useDomainSuggestions( return { allDomainSuggestions, state, errorMessage, retryRequest }; }, - [ domainSearch, domainCategory, quantity ] + [ domainSearch, domainCategory, quantity, locale, extraOptions ] ); } diff --git a/packages/eslint-plugin-package-json/package.json b/packages/eslint-plugin-package-json/package.json index f2b4045c8618c..94f9a43475c04 100644 --- a/packages/eslint-plugin-package-json/package.json +++ b/packages/eslint-plugin-package-json/package.json @@ -18,7 +18,7 @@ ], "license": "GPL-2.0-or-later", "dependencies": { - "@wordpress/npm-package-json-lint-config": "^4.1.2", + "@wordpress/npm-package-json-lint-config": "^4.7.0", "eslint-plugin-json-es": "^1.5.7", "esquery": "^1.4.0", "npm-package-json-lint": "^5.4.2" diff --git a/packages/global-styles/package.json b/packages/global-styles/package.json index c80f79ac5cb92..02cedfe625ba8 100644 --- a/packages/global-styles/package.json +++ b/packages/global-styles/package.json @@ -29,11 +29,11 @@ "watch": "tsc --build ./tsconfig.json --watch" }, "dependencies": { - "@wordpress/block-editor": "^9.1.0", - "@wordpress/components": "^19.15.0", - "@wordpress/compose": "^5.7.0", - "@wordpress/edit-site": "^4.6.0", - "@wordpress/keycodes": "^3.9.0", + "@wordpress/block-editor": "^10.5.0", + "@wordpress/components": "^22.1.0", + "@wordpress/compose": "^5.20.0", + "@wordpress/edit-site": "^4.19.0", + "@wordpress/keycodes": "^3.22.0", "classnames": "^2.3.1", "i18n-calypso": "workspace:^", "react": "^17.0.2", diff --git a/packages/help-center/package.json b/packages/help-center/package.json index 443a7aa5f3adf..ae87c4764c8ad 100644 --- a/packages/help-center/package.json +++ b/packages/help-center/package.json @@ -37,11 +37,11 @@ "@automattic/viewport": "workspace:^", "@automattic/viewport-react": "workspace:^", "@popperjs/core": "^2.10.2", - "@wordpress/base-styles": "^4.5.0", - "@wordpress/components": "^19.15.0", - "@wordpress/i18n": "^4.9.0", - "@wordpress/icons": "^9.0.0", - "@wordpress/primitives": "^3.7.0", + "@wordpress/base-styles": "^4.13.0", + "@wordpress/components": "^22.1.0", + "@wordpress/i18n": "^4.22.0", + "@wordpress/icons": "^9.13.0", + "@wordpress/primitives": "^3.20.0", "classnames": "^2.3.1", "react": "^17.0.2", "react-dom": "^17.0.2", @@ -56,8 +56,8 @@ "typescript": "^4.7.4" }, "peerDependencies": { - "@wordpress/data": "^6.1.5", - "@wordpress/element": "^4.5.0", + "@wordpress/data": "^7.6.0", + "@wordpress/element": "^4.20.0", "react": "^17.0.2", "react-dom": "^17.0.2", "reakit-utils": "^0.15.1", diff --git a/packages/help-center/src/components/help-center-contact-form.tsx b/packages/help-center/src/components/help-center-contact-form.tsx index 503e2ba1171d7..ed1addbb9fe0f 100644 --- a/packages/help-center/src/components/help-center-contact-form.tsx +++ b/packages/help-center/src/components/help-center-contact-form.tsx @@ -40,6 +40,7 @@ import { SitePicker } from '../types'; import { BackButton } from './back-button'; import { HelpCenterOwnershipNotice } from './help-center-notice'; import { SibylArticles } from './help-center-sibyl-articles'; +import type { HelpCenterSelect } from '@automattic/data-stores'; import './help-center-contact-form.scss'; export const SITE_STORE = 'automattic/site'; @@ -166,13 +167,14 @@ export const HelpCenterContactForm = () => { 'CURRENT_SITE' ); const { currentSite, subject, message, userDeclaredSiteUrl } = useSelect( ( select ) => { + const helpCenterSelect: HelpCenterSelect = select( HELP_CENTER_STORE ); return { - currentSite: select( HELP_CENTER_STORE ).getSite(), - subject: select( HELP_CENTER_STORE ).getSubject(), - message: select( HELP_CENTER_STORE ).getMessage(), - userDeclaredSiteUrl: select( HELP_CENTER_STORE ).getUserDeclaredSiteUrl(), + currentSite: helpCenterSelect.getSite(), + subject: helpCenterSelect.getSubject(), + message: helpCenterSelect.getMessage(), + userDeclaredSiteUrl: helpCenterSelect.getUserDeclaredSiteUrl(), }; - } ); + }, [] ); const { setSite, diff --git a/packages/help-center/src/components/help-center-container.tsx b/packages/help-center/src/components/help-center-container.tsx index b0c0f25ae5880..ed23d2b718be9 100644 --- a/packages/help-center/src/components/help-center-container.tsx +++ b/packages/help-center/src/components/help-center-container.tsx @@ -20,6 +20,7 @@ import HelpCenterContent from './help-center-content'; import HelpCenterFooter from './help-center-footer'; import HelpCenterHeader from './help-center-header'; import { HistoryRecorder } from './history-recorder'; +import type { HelpCenterSelect } from '@automattic/data-stores'; interface OptionalDraggableProps extends Partial< DraggableProps > { draggable: boolean; @@ -33,10 +34,13 @@ const OptionalDraggable: FC< OptionalDraggableProps > = ( { draggable, ...props }; const HelpCenterContainer: React.FC< Container > = ( { handleClose, hidden } ) => { - const { show, isMinimized } = useSelect( ( select ) => ( { - show: select( HELP_CENTER_STORE ).isHelpCenterShown(), - isMinimized: select( HELP_CENTER_STORE ).getIsMinimized(), - } ) ); + const { show, isMinimized } = useSelect( + ( select ) => ( { + show: ( select( HELP_CENTER_STORE ) as HelpCenterSelect ).isHelpCenterShown(), + isMinimized: ( select( HELP_CENTER_STORE ) as HelpCenterSelect ).getIsMinimized(), + } ), + [] + ); const { setIsMinimized } = useDispatch( HELP_CENTER_STORE ); @@ -47,8 +51,9 @@ const HelpCenterContainer: React.FC< Container > = ( { handleClose, hidden } ) = } ); const { data: supportAvailability } = useSupportAvailability( 'CHAT' ); const { data } = useHappychatAvailable( Boolean( supportAvailability?.is_user_eligible ) ); - const { history, index } = useSelect( ( select ) => - select( HELP_CENTER_STORE ).getRouterState() + const { history, index } = useSelect( + ( select ) => ( select( HELP_CENTER_STORE ) as HelpCenterSelect ).getRouterState(), + [] ); const onDismiss = () => { diff --git a/packages/help-center/src/components/help-center-header.tsx b/packages/help-center/src/components/help-center-header.tsx index ee9c0315a4a90..43329d4b25dfb 100644 --- a/packages/help-center/src/components/help-center-header.tsx +++ b/packages/help-center/src/components/help-center-header.tsx @@ -7,6 +7,7 @@ import { useCallback } from 'react'; import { Route, Switch, useLocation } from 'react-router-dom'; import { HELP_CENTER_STORE } from '../stores'; import type { Header } from '../types'; +import type { HelpCenterSelect } from '@automattic/data-stores'; export function ArticleTitle() { const location = useLocation(); @@ -49,7 +50,10 @@ const SupportModeTitle = () => { }; const HelpCenterHeader = ( { isMinimized = false, onMinimize, onMaximize, onDismiss }: Header ) => { - const unreadCount = useSelect( ( select ) => select( HELP_CENTER_STORE ).getUnreadCount() ); + const unreadCount = useSelect( + ( select ) => ( select( HELP_CENTER_STORE ) as HelpCenterSelect ).getUnreadCount(), + [] + ); const classNames = classnames( 'help-center__container-header' ); const { __ } = useI18n(); const formattedUnreadCount = unreadCount > 9 ? '9+' : unreadCount; diff --git a/packages/help-center/src/components/help-center-launchpad.tsx b/packages/help-center/src/components/help-center-launchpad.tsx index 01e0499d3016f..14aaf83d951cc 100644 --- a/packages/help-center/src/components/help-center-launchpad.tsx +++ b/packages/help-center/src/components/help-center-launchpad.tsx @@ -9,6 +9,7 @@ import { useI18n } from '@wordpress/react-i18n'; import { useSelector } from 'react-redux'; import { getSectionName, getSelectedSiteId } from 'calypso/state/ui/selectors'; import { SITE_STORE } from '../stores'; +import type { SiteSelect } from '@automattic/data-stores'; const getEnvironmentHostname = () => { try { @@ -30,7 +31,10 @@ export const HelpCenterLaunchpad = () => { const { __ } = useI18n(); const siteId = useSelector( ( state ) => getSelectedSiteId( state ) ); - const site = useSelect( ( select ) => siteId && select( SITE_STORE ).getSite( siteId ) ); + const site = useSelect( + ( select ) => siteId && ( select( SITE_STORE ) as SiteSelect ).getSite( siteId ), + [ siteId ] + ); let siteIntent = site && site?.options?.site_intent; let siteSlug = site && new URL( site.URL ).host; diff --git a/packages/help-center/src/components/help-center-more-resources.tsx b/packages/help-center/src/components/help-center-more-resources.tsx index a2fb0a90f2bd6..2608bb5e4beb7 100644 --- a/packages/help-center/src/components/help-center-more-resources.tsx +++ b/packages/help-center/src/components/help-center-more-resources.tsx @@ -14,6 +14,7 @@ import { getUserPurchases } from 'calypso/state/purchases/selectors'; import { getSectionName } from 'calypso/state/ui/selectors'; import { NewReleases } from '../icons'; import { HELP_CENTER_STORE } from '../stores'; +import type { HelpCenterSelect } from '@automattic/data-stores'; const circle = ( @@ -21,6 +22,10 @@ const circle = ( ); +type CoreDataPlaceholder = { + hasFinishedResolution: ( ...args: unknown[] ) => boolean; +}; + export const HelpCenterMoreResources = () => { const { __ } = useI18n(); const sectionName = useSelector( getSectionName ); @@ -36,14 +41,19 @@ export const HelpCenterMoreResources = () => { }; } ); - const { hasSeenWhatsNewModal, doneLoading } = useSelect( ( select ) => ( { - hasSeenWhatsNewModal: select( HELP_CENTER_STORE ).getHasSeenWhatsNewModal(), - doneLoading: select( 'core/data' ).hasFinishedResolution( - HELP_CENTER_STORE, - 'getHasSeenWhatsNewModal', - [] - ), - } ) ); + const { hasSeenWhatsNewModal, doneLoading } = useSelect( + ( select ) => ( { + hasSeenWhatsNewModal: ( + select( HELP_CENTER_STORE ) as HelpCenterSelect + ).getHasSeenWhatsNewModal(), + doneLoading: ( select( 'core/data' ) as CoreDataPlaceholder ).hasFinishedResolution( + HELP_CENTER_STORE, + 'getHasSeenWhatsNewModal', + [] + ), + } ), + [] + ); const { setHasSeenWhatsNewModal } = useDispatch( HELP_CENTER_STORE ); diff --git a/packages/help-center/src/components/help-center-search.tsx b/packages/help-center/src/components/help-center-search.tsx index 96c016fd5dce4..0dae0d86c262b 100644 --- a/packages/help-center/src/components/help-center-search.tsx +++ b/packages/help-center/src/components/help-center-search.tsx @@ -15,6 +15,7 @@ import HelpCenterSearchResults from './help-center-search-results'; import './help-center-search.scss'; import './help-center-launchpad.scss'; import { SibylArticles } from './help-center-sibyl-articles'; +import type { SiteSelect } from '@automattic/data-stores'; export const HelpCenterSearch = () => { const history = useHistory(); @@ -25,7 +26,10 @@ export const HelpCenterSearch = () => { const [ searchQuery, setSearchQuery ] = useState( query || '' ); const siteId = useSelector( ( state ) => getSelectedSiteId( state ) ); - const site = useSelect( ( select ) => siteId && select( SITE_STORE ).getSite( siteId ) ); + const site = useSelect( + ( select ) => siteId && ( select( SITE_STORE ) as SiteSelect ).getSite( siteId ), + [ siteId ] + ); let launchpadEnabled = site && site?.options.launchpad_screen === 'full'; if ( ! launchpadEnabled ) { diff --git a/packages/help-center/src/components/help-center.tsx b/packages/help-center/src/components/help-center.tsx index b3094e6b2af1b..335b8644996bf 100644 --- a/packages/help-center/src/components/help-center.tsx +++ b/packages/help-center/src/components/help-center.tsx @@ -17,7 +17,7 @@ import { useStillNeedHelpURL } from '../hooks/use-still-need-help-url'; import { HELP_CENTER_STORE, USER_STORE, SITE_STORE } from '../stores'; import { Container } from '../types'; import HelpCenterContainer from './help-center-container'; - +import type { HelpCenterSelect, SiteSelect, UserSelect } from '@automattic/data-stores'; import '../styles.scss'; const HelpCenter: React.FC< Container > = ( { handleClose, hidden } ) => { @@ -28,10 +28,13 @@ const HelpCenter: React.FC< Container > = ( { handleClose, hidden } ) => { const { setUnreadCount } = useDispatch( HELP_CENTER_STORE ); const { setSite } = useDispatch( HELP_CENTER_STORE ); - const { show, isMinimized } = useSelect( ( select ) => ( { - isMinimized: select( HELP_CENTER_STORE ).getIsMinimized(), - show: select( HELP_CENTER_STORE ).isHelpCenterShown(), - } ) ); + const { show, isMinimized } = useSelect( + ( select ) => ( { + isMinimized: ( select( HELP_CENTER_STORE ) as HelpCenterSelect ).getIsMinimized(), + show: ( select( HELP_CENTER_STORE ) as HelpCenterSelect ).isHelpCenterShown(), + } ), + [] + ); const { unreadCount, closeChat } = useHCWindowCommunicator( isMinimized || ! show ); @@ -48,10 +51,13 @@ const HelpCenter: React.FC< Container > = ( { handleClose, hidden } ) => { const siteId = useSelector( ( state ) => getSelectedSiteId( state ) ); const primarySiteId = useSelector( ( state ) => getPrimarySiteId( state ) ); - useSelect( ( select ) => select( USER_STORE ).getCurrentUser() ); + useSelect( ( select ) => ( select( USER_STORE ) as UserSelect ).getCurrentUser(), [] ); const currentSite = window?.helpCenterData?.currentSite; - const site = useSelect( ( select ) => select( SITE_STORE ).getSite( siteId || primarySiteId ) ); + const site = useSelect( + ( select ) => ( select( SITE_STORE ) as SiteSelect ).getSite( siteId || primarySiteId ), + [ siteId || primarySiteId ] + ); setSite( currentSite ? currentSite : site ); useSupportAvailability( 'CHAT' ); diff --git a/packages/help-center/src/components/help-icon.tsx b/packages/help-center/src/components/help-icon.tsx index 83f8d607ff9cf..f659b8a7c3036 100644 --- a/packages/help-center/src/components/help-icon.tsx +++ b/packages/help-center/src/components/help-icon.tsx @@ -1,17 +1,24 @@ import { useSelect } from '@wordpress/data'; import { forwardRef } from 'react'; import { HELP_CENTER_STORE } from '../stores'; +import type { HelpCenterSelect } from '@automattic/data-stores'; + +type CoreDataPlaceholder = { + hasFinishedResolution: ( ...args: unknown[] ) => boolean; +}; const HelpIcon = forwardRef< SVGSVGElement >( ( _, ref ) => { const { unreadCount, doneLoading, hasSeenWhatsNewModal } = useSelect( ( select ) => ( { - unreadCount: select( HELP_CENTER_STORE ).getUnreadCount(), - doneLoading: select( 'core/data' ).hasFinishedResolution( + unreadCount: ( select( HELP_CENTER_STORE ) as HelpCenterSelect ).getUnreadCount(), + doneLoading: ( select( 'core/data' ) as CoreDataPlaceholder ).hasFinishedResolution( HELP_CENTER_STORE, 'getHasSeenWhatsNewModal', [] ), - hasSeenWhatsNewModal: select( HELP_CENTER_STORE ).getHasSeenWhatsNewModal(), + hasSeenWhatsNewModal: ( + select( HELP_CENTER_STORE ) as HelpCenterSelect + ).getHasSeenWhatsNewModal(), } ), [] ); diff --git a/packages/help-center/src/happychat-window-communicator.ts b/packages/help-center/src/happychat-window-communicator.ts index 50324e2da4101..e2070ad7ea320 100644 --- a/packages/help-center/src/happychat-window-communicator.ts +++ b/packages/help-center/src/happychat-window-communicator.ts @@ -1,15 +1,9 @@ -/* eslint-disable no-restricted-imports */ -/** - * External Dependencies - */ import { useHappychatAuth, happychatAuthQueryKey } from '@automattic/happychat-connection'; import { useDispatch, useSelect } from '@wordpress/data'; import { useEffect, useState } from '@wordpress/element'; import { useQueryClient } from 'react-query'; -/** - * Internal Dependencies - */ import { HELP_CENTER_STORE } from './stores'; +import type { HelpCenterSelect } from '@automattic/data-stores'; /** * This hook is the bridge between HappyChat and Help Center. @@ -22,14 +16,15 @@ import { HELP_CENTER_STORE } from './stores'; export function useHCWindowCommunicator( isMinimized: boolean ) { const { supportSite, subject, message, chatTag, iframe } = useSelect( ( select ) => { + const helpCenterSelect: HelpCenterSelect = select( HELP_CENTER_STORE ); return { - supportSite: select( HELP_CENTER_STORE ).getSite(), - subject: select( HELP_CENTER_STORE ).getSubject(), - message: select( HELP_CENTER_STORE ).getMessage(), - chatTag: select( HELP_CENTER_STORE ).getChatTag(), - iframe: select( HELP_CENTER_STORE ).getIframe(), + supportSite: helpCenterSelect.getSite(), + subject: helpCenterSelect.getSubject(), + message: helpCenterSelect.getMessage(), + chatTag: helpCenterSelect.getChatTag(), + iframe: helpCenterSelect.getIframe(), }; - } ); + }, [] ); const queryClient = useQueryClient(); const [ unreadCount, setUnreadCount ] = useState( 0 ); const [ chatStatus, setChatStatus ] = useState( '' ); diff --git a/packages/i18n-calypso/package.json b/packages/i18n-calypso/package.json index 1b93d3e176eb8..94e13acf6a451 100644 --- a/packages/i18n-calypso/package.json +++ b/packages/i18n-calypso/package.json @@ -20,7 +20,7 @@ "@automattic/interpolate-components": "workspace:^", "@babel/runtime": "^7.17.2", "@tannin/sprintf": "^1.1.0", - "@wordpress/compose": "^5.7.0", + "@wordpress/compose": "^5.20.0", "debug": "^4.3.3", "events": "^3.0.0", "hash.js": "^1.1.5", diff --git a/packages/i18n-utils/package.json b/packages/i18n-utils/package.json index 20dde3150ca9b..8c082ecabe050 100644 --- a/packages/i18n-utils/package.json +++ b/packages/i18n-utils/package.json @@ -30,8 +30,8 @@ "dependencies": { "@automattic/calypso-url": "workspace:^", "@automattic/languages": "workspace:^", - "@wordpress/compose": "^5.7.0", - "@wordpress/i18n": "^4.9.0", + "@wordpress/compose": "^5.20.0", + "@wordpress/i18n": "^4.22.0", "react": "^17.0.2", "tslib": "^2.3.0" }, diff --git a/packages/language-picker/package.json b/packages/language-picker/package.json index 9b732433060b9..52dd6b11f0801 100644 --- a/packages/language-picker/package.json +++ b/packages/language-picker/package.json @@ -30,13 +30,13 @@ "@automattic/languages": "workspace:^", "@automattic/search": "workspace:^", "@babel/runtime": "^7.17.2", - "@wordpress/base-styles": "^4.5.0", - "@wordpress/components": "^19.15.0", - "@wordpress/i18n": "^4.9.0", - "@wordpress/react-i18n": "^3.7.0" + "@wordpress/base-styles": "^4.13.0", + "@wordpress/components": "^22.1.0", + "@wordpress/i18n": "^4.22.0", + "@wordpress/react-i18n": "^3.20.0" }, "peerDependencies": { - "@wordpress/data": "^6.7.0", + "@wordpress/data": "^7.6.0", "react": "^17.0.2", "react-dom": "^17.0.2", "reakit-utils": "^0.15.1", diff --git a/packages/launch/package.json b/packages/launch/package.json index 6f0702f3cc86f..a96f3e3cbedc6 100644 --- a/packages/launch/package.json +++ b/packages/launch/package.json @@ -36,10 +36,10 @@ "@automattic/onboarding": "workspace:^", "@automattic/plans-grid": "workspace:^", "@automattic/shopping-cart": "workspace:^", - "@wordpress/components": "^19.15.0", - "@wordpress/icons": "^9.0.0", - "@wordpress/react-i18n": "^3.7.0", - "@wordpress/url": "^3.10.0", + "@wordpress/components": "^22.1.0", + "@wordpress/icons": "^9.13.0", + "@wordpress/react-i18n": "^3.20.0", + "@wordpress/url": "^3.23.0", "classnames": "^2.3.1", "react-router-dom": "^5.1.2", "tslib": "^2.3.0", @@ -50,16 +50,16 @@ "@automattic/calypso-typescript-config": "workspace:^", "@automattic/typography": "workspace:^", "@testing-library/react": "^12.1.3", - "@wordpress/base-styles": "^4.5.0", + "@wordpress/base-styles": "^4.13.0", "copyfiles": "^2.3.0", "react": "^17.0.2", "react-dom": "^17.0.2", "typescript": "^4.7.4" }, "peerDependencies": { - "@wordpress/data": "^6.7.0", - "@wordpress/element": "^4.5.0", - "@wordpress/i18n": "^4.7.0", + "@wordpress/data": "^7.6.0", + "@wordpress/element": "^4.20.0", + "@wordpress/i18n": "^4.22.0", "reakit-utils": "^0.15.1", "redux": "^4.1.2" }, diff --git a/packages/launch/src/focused-launch/index.tsx b/packages/launch/src/focused-launch/index.tsx index 66fc6107dd118..82fd7db2f48fd 100644 --- a/packages/launch/src/focused-launch/index.tsx +++ b/packages/launch/src/focused-launch/index.tsx @@ -9,6 +9,7 @@ import PlanDetails from './plan-details'; import { Route as FocusedLaunchRoute } from './route'; import Success from './success'; import Summary from './summary'; +import type { LaunchSelect } from '@automattic/data-stores'; import './style.scss'; @@ -16,10 +17,11 @@ const FocusedLaunch: React.FunctionComponent = () => { const { hasPaidPlan, isSiteLaunched, isSiteLaunching } = useSite(); const [ hasSelectedDomain, selectedPlanProductId ] = useSelect( ( select ) => { - const { planProductId } = select( LAUNCH_STORE ).getState(); + const launchSelect: LaunchSelect = select( LAUNCH_STORE ); + const { planProductId } = launchSelect.getState(); - return [ select( LAUNCH_STORE ).hasSelectedDomainOrSubdomain(), planProductId ]; - } ); + return [ launchSelect.hasSelectedDomainOrSubdomain(), planProductId ]; + }, [] ); // @TODO: extract to some hook for reusability (Eg: use-products-from-cart) // If there is no selected domain, but there is a domain in cart, diff --git a/packages/launch/src/focused-launch/plan-details/index.tsx b/packages/launch/src/focused-launch/plan-details/index.tsx index 46946f327d1f6..4949e5b9b71a2 100644 --- a/packages/launch/src/focused-launch/plan-details/index.tsx +++ b/packages/launch/src/focused-launch/plan-details/index.tsx @@ -9,12 +9,17 @@ import * as React from 'react'; import { useHistory } from 'react-router-dom'; import { LAUNCH_STORE } from '../../stores'; import GoBackButton from '../go-back-button'; +import type { LaunchSelect } from '@automattic/data-stores'; const PlanDetails: React.FunctionComponent = () => { const locale = useLocale(); - const domain = useSelect( ( select ) => select( LAUNCH_STORE ).getSelectedDomain() ); - const selectedPlanProductId = useSelect( ( select ) => - select( LAUNCH_STORE ).getSelectedPlanProductId() + const domain = useSelect( + ( select ) => ( select( LAUNCH_STORE ) as LaunchSelect ).getSelectedDomain(), + [] + ); + const selectedPlanProductId = useSelect( + ( select ) => ( select( LAUNCH_STORE ) as LaunchSelect ).getSelectedPlanProductId(), + [] ); const history = useHistory(); diff --git a/packages/launch/src/focused-launch/success/index.tsx b/packages/launch/src/focused-launch/success/index.tsx index ddd88e6e2065b..1859b9537ca2e 100644 --- a/packages/launch/src/focused-launch/success/index.tsx +++ b/packages/launch/src/focused-launch/success/index.tsx @@ -9,6 +9,7 @@ import * as React from 'react'; import LaunchContext from '../../context'; import { useSiteDomains, useHasEcommercePlan } from '../../hooks'; import { LAUNCH_STORE, SITE_STORE } from '../../stores'; +import type { LaunchSelect, SiteSelect } from '@automattic/data-stores'; import './style.scss'; @@ -19,12 +20,12 @@ const Success: React.FunctionComponent = () => { React.useContext( LaunchContext ); const isSiteLaunching = useSelect( - ( select ) => select( SITE_STORE ).isSiteLaunching( siteId ), - [] + ( select ) => ( select( SITE_STORE ) as SiteSelect ).isSiteLaunching( siteId ), + [ siteId ] ); const [ isSelectedPlanPaid, selectedDomain ] = useSelect( ( select ) => { - const launchStore = select( LAUNCH_STORE ); + const launchStore: LaunchSelect = select( LAUNCH_STORE ); return [ launchStore.isSelectedPlanPaid(), launchStore.getSelectedDomain() ]; }, [] ); diff --git a/packages/launch/src/focused-launch/summary/index.tsx b/packages/launch/src/focused-launch/summary/index.tsx index 2cbbebfc04e30..72c3528561f4f 100644 --- a/packages/launch/src/focused-launch/summary/index.tsx +++ b/packages/launch/src/focused-launch/summary/index.tsx @@ -32,6 +32,7 @@ import FocusedLaunchSummaryItem, { TrailingContentSide, } from './focused-launch-summary-item'; import type { Plan, PlanProduct } from '../../stores'; +import type { LaunchSelect, PlansSelect } from '@automattic/data-stores'; import './style.scss'; @@ -279,19 +280,24 @@ const PlanStep: React.FunctionComponent< PlanStepProps > = ( { const { setPlanProductId } = useDispatch( LAUNCH_STORE ); - const [ selectedPlanProductId, billingPeriod ] = useSelect( ( select ) => [ - select( LAUNCH_STORE ).getSelectedPlanProductId(), - select( LAUNCH_STORE ).getLastPlanBillingPeriod(), - ] ); - - const { selectedPlan, selectedPlanProduct } = useSelect( ( select ) => { - const plansStore = select( PLANS_STORE ); - + const { selectedPlanProductId, billingPeriod } = useSelect( ( select ) => { return { - selectedPlan: plansStore.getPlanByProductId( selectedPlanProductId, locale ), - selectedPlanProduct: plansStore.getPlanProductById( selectedPlanProductId ), + selectedPlanProductId: ( select( LAUNCH_STORE ) as LaunchSelect ).getSelectedPlanProductId(), + billingPeriod: ( select( LAUNCH_STORE ) as LaunchSelect ).getLastPlanBillingPeriod(), }; - } ); + }, [] ); + + const { selectedPlan, selectedPlanProduct } = useSelect( + ( select ) => { + const plansStore: PlansSelect = select( PLANS_STORE ); + + return { + selectedPlan: plansStore.getPlanByProductId( selectedPlanProductId, locale ), + selectedPlanProduct: plansStore.getPlanProductById( selectedPlanProductId ), + }; + }, + [ selectedPlanProductId, locale ] + ); // persist non-default selected paid plan if it's paid in order to keep displaying it in the plan picker const [ nonDefaultPaidPlan, setNonDefaultPaidPlan ] = React.useState< Plan | undefined >(); @@ -510,21 +516,22 @@ type StepIndexRenderFunction = ( renderOptions: { const Summary: React.FunctionComponent = () => { const { siteId } = React.useContext( LaunchContext ); - const [ hasSelectedDomain, isSiteTitleStepVisible, selectedDomain, selectedPlanProductId ] = + const { hasSelectedDomain, isSiteTitleStepVisible, selectedDomain, selectedPlanProductId } = useSelect( ( select ) => { - const launchStore = select( LAUNCH_STORE ); - const { isSiteTitleStepVisible, domain, planProductId } = launchStore.getState(); - - return [ - launchStore.hasSelectedDomainOrSubdomain(), - isSiteTitleStepVisible, - domain, - planProductId, - ]; + const launchStore: LaunchSelect = select( LAUNCH_STORE ); + const launchStoreState = launchStore.getState(); + const { domain, planProductId } = launchStoreState; + + return { + hasSelectedDomain: launchStore.hasSelectedDomainOrSubdomain(), + isSiteTitleStepVisible: launchStoreState.isSiteTitleStepVisible, + selectedDomain: domain, + selectedPlanProductId: planProductId, + }; }, [] ); const isSelectedPlanPaid = useSelect( - ( select ) => select( LAUNCH_STORE ).isSelectedPlanPaid(), + ( select ) => ( select( LAUNCH_STORE ) as LaunchSelect ).isSelectedPlanPaid(), [] ); diff --git a/packages/launch/src/hooks/use-cart.ts b/packages/launch/src/hooks/use-cart.ts index 91600ee92daee..5f6f379e7aa5d 100644 --- a/packages/launch/src/hooks/use-cart.ts +++ b/packages/launch/src/hooks/use-cart.ts @@ -5,6 +5,7 @@ import LaunchContext from '../context'; import { useSiteDomains, useHasEcommercePlan } from '../hooks'; import { LAUNCH_STORE, SITE_STORE, PLANS_STORE } from '../stores'; import { getDomainProduct, getPlanProductForFlow } from '../utils'; +import type { LaunchSelect, PlansSelect } from '@automattic/data-stores'; type LaunchCart = { goToCheckout: () => Promise< void >; // used in gutenboarding-launch @@ -17,15 +18,18 @@ export function useCart(): LaunchCart { const locale = useLocale(); - const [ planProductId, domain ] = useSelect( ( select ) => [ - select( LAUNCH_STORE ).getSelectedPlanProductId(), - select( LAUNCH_STORE ).getSelectedDomain(), - ] ); + const { planProductId, domain } = useSelect( + ( select ) => ( { + planProductId: ( select( LAUNCH_STORE ) as LaunchSelect ).getSelectedPlanProductId(), + domain: ( select( LAUNCH_STORE ) as LaunchSelect ).getSelectedDomain(), + } ), + [] + ); const { planProduct, isEcommercePlan } = useSelect( ( select ) => { - const plansStore = select( PLANS_STORE ); - const plan = plansStore.getPlanByProductId( planProductId, locale ); + const plansStore: PlansSelect = select( PLANS_STORE ); + const plan = plansStore.getPlanByProductId( planProductId as number, locale ); return { planProduct: plansStore.getPlanProductById( planProductId as number ), isEcommercePlan: plansStore.isPlanEcommerce( plan?.periodAgnosticSlug ), diff --git a/packages/launch/src/hooks/use-domain-search.ts b/packages/launch/src/hooks/use-domain-search.ts index 65a945051c679..1ab422c4ad465 100644 --- a/packages/launch/src/hooks/use-domain-search.ts +++ b/packages/launch/src/hooks/use-domain-search.ts @@ -4,6 +4,7 @@ import { useSelect, useDispatch } from '@wordpress/data'; import { LAUNCH_STORE } from '../stores'; import { useSiteDomains } from './use-site-domains'; import { useSite, useTitle } from './'; +import type { LaunchSelect } from '@automattic/data-stores'; export function useDomainSearch(): { domainSearch: string; @@ -11,7 +12,7 @@ export function useDomainSearch(): { setDomainSearch: ( search: string ) => void; } { const existingDomainSearch = useSelect( - ( select ) => select( LAUNCH_STORE ).getDomainSearch(), + ( select ) => ( select( LAUNCH_STORE ) as LaunchSelect ).getDomainSearch(), [] ); const { isDefaultTitle, title } = useTitle(); diff --git a/packages/launch/src/hooks/use-domain-selection.ts b/packages/launch/src/hooks/use-domain-selection.ts index b5f8387fcc4fe..fb3a36f53d37e 100644 --- a/packages/launch/src/hooks/use-domain-selection.ts +++ b/packages/launch/src/hooks/use-domain-selection.ts @@ -7,6 +7,7 @@ import { LAUNCH_STORE, SITE_STORE, PLANS_STORE, DOMAIN_SUGGESTIONS_STORE } from import { isDomainProduct } from '../utils'; import { useSiteDomains } from './use-site-domains'; import type { DomainProduct } from '../utils'; +import type { DomainSuggestionsSelect, LaunchSelect, PlansSelect } from '@automattic/data-stores'; import type { ResponseCartProduct } from '@automattic/shopping-cart'; export function useDomainProductFromCart(): DomainProduct | undefined { @@ -40,7 +41,9 @@ export function useDomainSuggestionFromCart(): DomainSuggestions.DomainSuggestio if ( ! domainName ) { return; } - return select( DOMAIN_SUGGESTIONS_STORE ).isAvailable( domainName ); + return ( select( DOMAIN_SUGGESTIONS_STORE ) as DomainSuggestionsSelect ).isAvailable( + domainName + ); }, [ domainName ] ); @@ -91,9 +94,10 @@ export function useDomainSelection(): DomainSelection { domain: selectedDomain, planProductId, confirmedDomainSelection, - } = useSelect( ( select ) => select( LAUNCH_STORE ).getState() ); - const isPlanFree = useSelect( ( select ) => - select( PLANS_STORE ).isPlanProductFree( planProductId ) + } = useSelect( ( select ) => ( select( LAUNCH_STORE ) as LaunchSelect ).getState(), [] ); + const isPlanFree = useSelect( + ( select ) => ( select( PLANS_STORE ) as PlansSelect ).isPlanProductFree( planProductId ), + [ planProductId ] ); const { siteSubdomain, hasPaidDomain, sitePrimaryDomain } = useSiteDomains(); diff --git a/packages/launch/src/hooks/use-domain-suggestion.ts b/packages/launch/src/hooks/use-domain-suggestion.ts index 620408572d771..6dedf4ef704ed 100644 --- a/packages/launch/src/hooks/use-domain-suggestion.ts +++ b/packages/launch/src/hooks/use-domain-suggestion.ts @@ -2,7 +2,7 @@ import { useLocale } from '@automattic/i18n-utils'; import { useSelect } from '@wordpress/data'; import { DOMAIN_SUGGESTIONS_STORE } from '../stores'; import { useDomainSearch } from './'; -import type { DomainSuggestions } from '@automattic/data-stores'; +import type { DomainSuggestions, DomainSuggestionsSelect } from '@automattic/data-stores'; export function useDomainSuggestion(): DomainSuggestions.DomainSuggestion | undefined { const locale = useLocale(); @@ -13,15 +13,18 @@ export function useDomainSuggestion(): DomainSuggestions.DomainSuggestion | unde if ( ! domainSearch || domainSearch.length < 2 ) { return; } - return select( DOMAIN_SUGGESTIONS_STORE ).getDomainSuggestions( domainSearch, { - // Avoid `only_wordpressdotcom` — it seems to fail to find results sometimes - include_wordpressdotcom: false, - include_dotblogsubdomain: false, - quantity: 1, // this will give the recommended domain only - locale, - } ); + return ( select( DOMAIN_SUGGESTIONS_STORE ) as DomainSuggestionsSelect ).getDomainSuggestions( + domainSearch, + { + // Avoid `only_wordpressdotcom` — it seems to fail to find results sometimes + include_wordpressdotcom: false, + include_dotblogsubdomain: false, + quantity: 1, // this will give the recommended domain only + locale, + } + ); }, - [ domainSearch ] + [ domainSearch, locale ] )?.[ 0 ]; return suggestion; diff --git a/packages/launch/src/hooks/use-has-ecommerce-plan.ts b/packages/launch/src/hooks/use-has-ecommerce-plan.ts index d82fa83836423..fd3ad44fb45e6 100644 --- a/packages/launch/src/hooks/use-has-ecommerce-plan.ts +++ b/packages/launch/src/hooks/use-has-ecommerce-plan.ts @@ -1,18 +1,19 @@ import { useLocale } from '@automattic/i18n-utils'; import { useSelect } from '@wordpress/data'; import { LAUNCH_STORE, PLANS_STORE } from '../stores'; +import type { LaunchSelect, PlansSelect } from '@automattic/data-stores'; export function useHasEcommercePlan(): boolean { const locale = useLocale(); const planProductId = useSelect( - ( select ) => select( LAUNCH_STORE ).getSelectedPlanProductId(), + ( select ) => ( select( LAUNCH_STORE ) as LaunchSelect ).getSelectedPlanProductId(), [] ); const isEcommercePlan = useSelect( ( select ) => { - const plansStore = select( PLANS_STORE ); + const plansStore: PlansSelect = select( PLANS_STORE ); const plan = plansStore.getPlanByProductId( planProductId, locale ); return plansStore.isPlanEcommerce( plan?.periodAgnosticSlug ); }, diff --git a/packages/launch/src/hooks/use-on-launch.ts b/packages/launch/src/hooks/use-on-launch.ts index 8b86c6714e512..744e4389e277d 100644 --- a/packages/launch/src/hooks/use-on-launch.ts +++ b/packages/launch/src/hooks/use-on-launch.ts @@ -4,14 +4,19 @@ import LaunchContext from '../context'; import { useCart, useSiteDomains } from '../hooks'; import { LAUNCH_STORE, PLANS_STORE } from '../stores'; import { useSite } from './'; +import type { LaunchSelect, PlansSelect } from '@automattic/data-stores'; // Hook used exclusively in Step-by-step launch flow until it will be using Editor Checkout Modal export const useOnLaunch = () => { const { siteId, redirectTo } = useContext( LaunchContext ); - const { planProductId } = useSelect( ( select ) => select( LAUNCH_STORE ).getState() ); - const isPlanFree = useSelect( ( select ) => - select( PLANS_STORE ).isPlanProductFree( planProductId ) + const { planProductId } = useSelect( + ( select ) => ( select( LAUNCH_STORE ) as LaunchSelect ).getState(), + [] + ); + const isPlanFree = useSelect( + ( select ) => ( select( PLANS_STORE ) as PlansSelect ).isPlanProductFree( planProductId ), + [ planProductId ] ); const { isSiteLaunched } = useSite(); diff --git a/packages/launch/src/hooks/use-plans.tsx b/packages/launch/src/hooks/use-plans.tsx index 73db42d33f7aa..7d9df0d450054 100644 --- a/packages/launch/src/hooks/use-plans.tsx +++ b/packages/launch/src/hooks/use-plans.tsx @@ -5,7 +5,7 @@ import LaunchContext from '../context'; import { PLANS_STORE, SITE_STORE } from '../stores'; import { isPlanProduct } from '../utils'; import type { PlanProductForFlow } from '../utils'; -import type { Plans } from '@automattic/data-stores'; +import type { Plans, PlansSelect } from '@automattic/data-stores'; import type { ResponseCartProduct } from '@automattic/shopping-cart'; export function usePlans( billingPeriod: Plans.PlanBillingPeriod = 'ANNUALLY' ): { @@ -18,7 +18,7 @@ export function usePlans( billingPeriod: Plans.PlanBillingPeriod = 'ANNUALLY' ): return useSelect( ( select ) => { - const plansStore = select( PLANS_STORE ); + const plansStore: PlansSelect = select( PLANS_STORE ); const defaultFreePlan = plansStore.getDefaultFreePlan( locale ); const defaultPaidPlan = plansStore.getDefaultPaidPlan( locale ); diff --git a/packages/launch/src/hooks/use-site-domains.ts b/packages/launch/src/hooks/use-site-domains.ts index 76f4bdc06089d..6b97039eb0741 100644 --- a/packages/launch/src/hooks/use-site-domains.ts +++ b/packages/launch/src/hooks/use-site-domains.ts @@ -2,13 +2,18 @@ import { useSelect } from '@wordpress/data'; import { useContext } from 'react'; import LaunchContext from '../context'; import { SITE_STORE } from '../stores'; +import type { SiteSelect } from '@automattic/data-stores'; export function useSiteDomains() { const { siteId } = useContext( LaunchContext ); - const sitePrimaryDomain = useSelect( ( select ) => - select( SITE_STORE ).getPrimarySiteDomain( siteId ) + const sitePrimaryDomain = useSelect( + ( select ) => ( select( SITE_STORE ) as SiteSelect ).getPrimarySiteDomain( siteId ), + [ siteId ] + ); + const siteSubdomain = useSelect( + ( select ) => ( select( SITE_STORE ) as SiteSelect ).getSiteSubdomain( siteId ), + [ siteId ] ); - const siteSubdomain = useSelect( ( select ) => select( SITE_STORE ).getSiteSubdomain( siteId ) ); const hasPaidDomain = sitePrimaryDomain && ! sitePrimaryDomain?.is_subdomain; return { diff --git a/packages/launch/src/hooks/use-site.ts b/packages/launch/src/hooks/use-site.ts index 76aed3c21bd9c..76da20af89c23 100644 --- a/packages/launch/src/hooks/use-site.ts +++ b/packages/launch/src/hooks/use-site.ts @@ -2,26 +2,27 @@ import { useSelect } from '@wordpress/data'; import { useContext } from 'react'; import LaunchContext from '../context'; import { SITE_STORE } from '../stores'; +import type { SiteSelect } from '@automattic/data-stores'; export function useSite() { const { siteId } = useContext( LaunchContext ); - const [ site, isSiteLaunched, isSiteLaunching, isLoading ] = useSelect( + const { site, isSiteLaunched, isSiteLaunching, isLoading } = useSelect( ( select ) => { - const siteStore = select( SITE_STORE ); + const siteStore: SiteSelect = select( SITE_STORE ); - return [ - siteStore.getSite( siteId ), - siteStore.isSiteLaunched( siteId ), - siteStore.isSiteLaunching( siteId ), - siteStore.isFetchingSiteDetails(), - ]; + return { + site: siteStore.getSite( siteId ), + isSiteLaunched: siteStore.isSiteLaunched( siteId ), + isSiteLaunching: siteStore.isSiteLaunching( siteId ), + isLoading: siteStore.isFetchingSiteDetails(), + }; }, [ siteId ] ); return { - sitePlan: site?.plan, + sitePlan: site && site?.plan, hasPaidPlan: site && ! site.plan?.is_free, // sometimes plan will not be available: https://github.com/Automattic/wp-calypso/pull/44895 isSiteLaunched, isSiteLaunching, diff --git a/packages/launch/src/hooks/use-title.ts b/packages/launch/src/hooks/use-title.ts index bbdf7062fa7df..a4d247fffcd44 100644 --- a/packages/launch/src/hooks/use-title.ts +++ b/packages/launch/src/hooks/use-title.ts @@ -5,6 +5,7 @@ import { useContext, useEffect } from 'react'; import { useDebouncedCallback } from 'use-debounce'; import LaunchContext from '../context'; import { SITE_STORE, LAUNCH_STORE } from '../stores'; +import type { LaunchSelect, SiteSelect } from '@automattic/data-stores'; export function useTitle() { const { siteId } = useContext( LaunchContext ); @@ -12,10 +13,13 @@ export function useTitle() { const locale = useLocale(); const existingSiteTitle = useSelect( - ( select ) => select( SITE_STORE ).getSiteTitle( siteId ), + ( select ) => ( select( SITE_STORE ) as SiteSelect ).getSiteTitle( siteId ), [ siteId ] ); - const launchSiteTitle = useSelect( ( select ) => select( LAUNCH_STORE ).getSiteTitle(), [] ); + const launchSiteTitle = useSelect( + ( select ) => ( select( LAUNCH_STORE ) as LaunchSelect ).getSiteTitle(), + [] + ); const updateTitle = useDispatch( LAUNCH_STORE ).setSiteTitle; const saveSiteTitle = useDispatch( SITE_STORE ).saveSiteTitle; diff --git a/packages/launch/src/launch/index.tsx b/packages/launch/src/launch/index.tsx index 384da8526611f..59774c4ca6b65 100644 --- a/packages/launch/src/launch/index.tsx +++ b/packages/launch/src/launch/index.tsx @@ -10,6 +10,7 @@ import LaunchContext, { LaunchContextProps } from '../context'; import FocusedLaunch from '../focused-launch'; import Success from '../focused-launch/success'; import { LAUNCH_STORE, SITE_STORE } from '../stores'; +import type { LaunchSelect } from '@automattic/data-stores'; import './styles.scss'; interface FocusedLaunchModalProps extends Omit< LaunchContextProps, 'flow' > { @@ -27,8 +28,9 @@ const FocusedLaunchModal: React.FunctionComponent< FocusedLaunchModalProps > = ( isInIframe, isLaunchImmediately, } ) => { - const { isModalDismissible, isModalTitleVisible } = useSelect( ( select ) => - select( LAUNCH_STORE ).getState() + const { isModalDismissible, isModalTitleVisible } = useSelect( + ( select ) => ( select( LAUNCH_STORE ) as LaunchSelect ).getState(), + [] ); const { launchSite } = useDispatch( SITE_STORE ); diff --git a/packages/mini-cart/package.json b/packages/mini-cart/package.json index 4d6ecb98fe016..1aebd8da6297c 100644 --- a/packages/mini-cart/package.json +++ b/packages/mini-cart/package.json @@ -43,8 +43,8 @@ "@automattic/shopping-cart": "workspace:^", "@automattic/wpcom-checkout": "workspace:^", "@emotion/styled": "^11.3.0", - "@wordpress/i18n": "^4.9.0", - "@wordpress/react-i18n": "^3.7.0", + "@wordpress/i18n": "^4.22.0", + "@wordpress/react-i18n": "^3.20.0", "debug": "^4.3.3" }, "devDependencies": { diff --git a/packages/onboarding/package.json b/packages/onboarding/package.json index 4b15a958efb86..b3348efbb32c8 100644 --- a/packages/onboarding/package.json +++ b/packages/onboarding/package.json @@ -31,10 +31,10 @@ "dependencies": { "@automattic/components": "workspace:^", "@automattic/data-stores": "workspace:^", - "@wordpress/components": "^19.15.0", - "@wordpress/data": "^6.9.0", - "@wordpress/icons": "^9.0.0", - "@wordpress/react-i18n": "^3.7.0", + "@wordpress/components": "^22.1.0", + "@wordpress/data": "^7.6.0", + "@wordpress/icons": "^9.13.0", + "@wordpress/react-i18n": "^3.20.0", "classnames": "^2.3.1", "react-router-dom": "^5.1.2", "tslib": "^2.3.0", @@ -44,7 +44,7 @@ "@automattic/calypso-typescript-config": "workspace:^", "@automattic/typography": "workspace:^", "@testing-library/react": "^12.1.3", - "@wordpress/base-styles": "^4.5.0", + "@wordpress/base-styles": "^4.13.0", "copyfiles": "^2.3.0", "css-loader": "^3.6.0", "history": "^5.1.0", @@ -57,7 +57,7 @@ "webpack": "^5.63.0" }, "peerDependencies": { - "@wordpress/i18n": "^4.7.0", + "@wordpress/i18n": "^4.22.0", "react": "^17.0.2", "reakit-utils": "^0.15.1" }, diff --git a/packages/page-pattern-modal/package.json b/packages/page-pattern-modal/package.json index 99cd3ecff223f..10dbbc45b9b6f 100644 --- a/packages/page-pattern-modal/package.json +++ b/packages/page-pattern-modal/package.json @@ -29,12 +29,12 @@ "dependencies": { "@automattic/onboarding": "workspace:^", "@automattic/typography": "workspace:^", - "@wordpress/block-editor": "^9.1.0", - "@wordpress/blocks": "^11.8.0", - "@wordpress/components": "^19.15.0", - "@wordpress/compose": "^5.7.0", - "@wordpress/element": "^4.7.0", - "@wordpress/i18n": "^4.9.0", + "@wordpress/block-editor": "^10.5.0", + "@wordpress/blocks": "^11.21.0", + "@wordpress/components": "^22.1.0", + "@wordpress/compose": "^5.20.0", + "@wordpress/element": "^4.20.0", + "@wordpress/i18n": "^4.22.0", "classnames": "^2.3.1", "debug": "^4.3.3", "lodash": "^4.17.21" @@ -49,7 +49,7 @@ "typescript": "^4.7.4" }, "peerDependencies": { - "@wordpress/data": "^6.7.0", + "@wordpress/data": "^7.6.0", "react": "^17.0.2", "reakit-utils": "^0.15.1", "redux": "^4.1.2" diff --git a/packages/page-pattern-modal/src/types.d.ts b/packages/page-pattern-modal/src/types.d.ts index e4d38b2ca9e4e..9484d9f328731 100644 --- a/packages/page-pattern-modal/src/types.d.ts +++ b/packages/page-pattern-modal/src/types.d.ts @@ -1 +1,20 @@ +declare module '@wordpress/blocks' { + export interface BlockInstance< T extends Record< string, any > = { [ k: string ]: any } > { + readonly attributes: T; + readonly clientId: string; + readonly innerBlocks: BlockInstance[]; + readonly isValid: boolean; + readonly name: string; + readonly originalContent?: string | undefined; + } + + export function parse( content: string ): BlockInstance[]; + + export function cloneBlock< T extends Record< string, any > >( + block: BlockInstance< T >, + mergeAttributes?: Partial< T >, + newInnerBlocks?: BlockInstance[] + ): BlockInstance< T >; +} + declare const __i18n_text_domain__: string; diff --git a/packages/pattern-picker/package.json b/packages/pattern-picker/package.json index ec7f69a6f183b..b831323c0b834 100644 --- a/packages/pattern-picker/package.json +++ b/packages/pattern-picker/package.json @@ -49,9 +49,9 @@ "webpack": "^5.68.0" }, "peerDependencies": { - "@wordpress/data": "^6.7.0", - "@wordpress/element": "^4.5.0", - "@wordpress/i18n": "^4.7.0", + "@wordpress/data": "^7.6.0", + "@wordpress/element": "^4.20.0", + "@wordpress/i18n": "^4.22.0", "debug": "^4.3.3", "react": "^17.0.2", "react-dom": "^17.0.2", diff --git a/packages/plans-grid/package.json b/packages/plans-grid/package.json index e16b0b672ff06..83510395661fb 100644 --- a/packages/plans-grid/package.json +++ b/packages/plans-grid/package.json @@ -32,11 +32,11 @@ "@automattic/data-stores": "workspace:^", "@automattic/i18n-utils": "workspace:^", "@automattic/onboarding": "workspace:^", - "@wordpress/components": "^19.15.0", - "@wordpress/compose": "^5.7.0", - "@wordpress/icons": "^9.0.0", - "@wordpress/primitives": "^3.7.0", - "@wordpress/react-i18n": "^3.7.0", + "@wordpress/components": "^22.1.0", + "@wordpress/compose": "^5.20.0", + "@wordpress/icons": "^9.13.0", + "@wordpress/primitives": "^3.20.0", + "@wordpress/react-i18n": "^3.20.0", "classnames": "^2.3.1", "debug": "^4.3.3", "lodash": "^4.17.21", @@ -46,14 +46,14 @@ "devDependencies": { "@automattic/calypso-typescript-config": "workspace:^", "@automattic/typography": "workspace:^", - "@wordpress/base-styles": "^4.5.0", + "@wordpress/base-styles": "^4.13.0", "prop-types": "^15.7.2", "typescript": "^4.7.4" }, "peerDependencies": { - "@wordpress/data": "^6.7.0", - "@wordpress/element": "^4.5.0", - "@wordpress/i18n": "^4.7.0", + "@wordpress/data": "^7.6.0", + "@wordpress/element": "^4.20.0", + "@wordpress/i18n": "^4.22.0", "react": "^17.0.2", "react-dom": "^17.0.2", "reakit-utils": "^0.15.1", diff --git a/packages/plans-grid/src/hooks/use-supported-plans.ts b/packages/plans-grid/src/hooks/use-supported-plans.ts index e0bf53cf32bdd..0d8f4b16ef9ab 100644 --- a/packages/plans-grid/src/hooks/use-supported-plans.ts +++ b/packages/plans-grid/src/hooks/use-supported-plans.ts @@ -1,22 +1,28 @@ import { useSelect } from '@wordpress/data'; import { PLANS_STORE } from '../stores'; -import type { Plans } from '@automattic/data-stores'; +import type { Plans, PlansSelect } from '@automattic/data-stores'; export const useSupportedPlans = ( locale: string, billingPeriod: Plans.PlanBillingPeriod ): { supportedPlans: Plans.Plan[]; maxAnnualDiscount: number } => { - const { supportedPlans, annualDiscounts } = useSelect( ( select ) => { - const supportedPlans = select( PLANS_STORE ).getSupportedPlans( locale ); - const annualDiscounts = supportedPlans - .map( ( plan ) => - select( PLANS_STORE ).getPlanProduct( plan.periodAgnosticSlug, billingPeriod ) - ) - .map( ( planProduct ) => planProduct?.annualDiscount ) - // ensure that no `undefined` values are passed on - .filter( ( value ) => !! value ) as number[]; - return { supportedPlans, annualDiscounts }; - } ); + const { supportedPlans, annualDiscounts } = useSelect( + ( select ) => { + const supportedPlans = ( select( PLANS_STORE ) as PlansSelect ).getSupportedPlans( locale ); + const annualDiscounts = supportedPlans + .map( ( plan ) => + ( select( PLANS_STORE ) as PlansSelect ).getPlanProduct( + plan.periodAgnosticSlug, + billingPeriod + ) + ) + .map( ( planProduct ) => planProduct?.annualDiscount ) + // ensure that no `undefined` values are passed on + .filter( ( value ) => !! value ) as number[]; + return { supportedPlans, annualDiscounts }; + }, + [ locale, billingPeriod ] + ); // Compute the highest annualDiscount value amongst all supported plans const maxAnnualDiscount = annualDiscounts.reduce( diff --git a/packages/plans-grid/src/plans-accordion-item/index.tsx b/packages/plans-grid/src/plans-accordion-item/index.tsx index beda5cf9cd991..7bb24ce79de13 100644 --- a/packages/plans-grid/src/plans-accordion-item/index.tsx +++ b/packages/plans-grid/src/plans-accordion-item/index.tsx @@ -7,7 +7,7 @@ import classNames from 'classnames'; import * as React from 'react'; import PlansFeatureList from '../plans-feature-list'; import { PLANS_STORE } from '../stores'; -import type { DomainSuggestions, Plans } from '@automattic/data-stores'; +import type { DomainSuggestions, Plans, PlansSelect } from '@automattic/data-stores'; import './style.scss'; @@ -56,8 +56,9 @@ const PlanAccordionItem: React.FunctionComponent< Props > = ( { const { __, hasTranslation } = useI18n(); const locale = useLocale(); - const planProduct = useSelect( ( select ) => - select( PLANS_STORE ).getPlanProduct( slug, billingPeriod ) + const planProduct = useSelect( + ( select ) => ( select( PLANS_STORE ) as PlansSelect ).getPlanProduct( slug, billingPeriod ), + [ slug, billingPeriod ] ); // show a nbsp in price while loading to prevent a jump in the UI diff --git a/packages/plans-grid/src/plans-accordion/index.tsx b/packages/plans-grid/src/plans-accordion/index.tsx index 167e8e5a3fe8e..552178edbbf0a 100644 --- a/packages/plans-grid/src/plans-accordion/index.tsx +++ b/packages/plans-grid/src/plans-accordion/index.tsx @@ -9,7 +9,13 @@ import PlanItem from '../plans-accordion-item'; import PlanItemPlaceholder from '../plans-accordion-item/plans-item-placeholder'; import { PLANS_STORE, WPCOM_FEATURES_STORE } from '../stores'; import type { DisabledPlansMap } from '../plans-table/types'; -import type { DomainSuggestions, Plans, WPCOMFeatures } from '@automattic/data-stores'; +import type { + DomainSuggestions, + Plans, + PlansSelect, + WPCOMFeatures, + WpcomFeaturesSelect, +} from '@automattic/data-stores'; import './style.scss'; @@ -50,19 +56,31 @@ const PlansAccordion: React.FunctionComponent< Props > = ( { const placeholderPlans = [ 1, 2, 3, 4 ]; // Primary plan - const { popularPlan, getPlanProduct } = useSelect( ( select ) => { - const plansStore = select( PLANS_STORE ); - return { - popularPlan: plansStore.getDefaultPaidPlan( locale ), - getPlanProduct: plansStore.getPlanProduct, - }; - } ); - const recommendedPlanSlug = useSelect( ( select ) => - select( WPCOM_FEATURES_STORE ).getRecommendedPlanSlug( selectedFeatures ) + const { popularPlan, getPlanProduct } = useSelect( + ( select ) => { + const plansStore: PlansSelect = select( PLANS_STORE ); + return { + popularPlan: plansStore.getDefaultPaidPlan( locale ), + getPlanProduct: plansStore.getPlanProduct, + }; + }, + [ locale ] + ); + const recommendedPlanSlug = useSelect( + ( select ) => + ( select( WPCOM_FEATURES_STORE ) as WpcomFeaturesSelect ).getRecommendedPlanSlug( + selectedFeatures + ), + [ selectedFeatures ] ); - const recommendedPlan = useSelect( ( select ) => - select( PLANS_STORE ).getPlanByPeriodAgnosticSlug( recommendedPlanSlug, locale ) + const recommendedPlan = useSelect( + ( select ) => + ( select( PLANS_STORE ) as PlansSelect ).getPlanByPeriodAgnosticSlug( + recommendedPlanSlug, + locale + ), + [ recommendedPlanSlug, locale ] ); const primaryPlan = recommendedPlan || popularPlan; diff --git a/packages/plans-grid/src/plans-details/index.tsx b/packages/plans-grid/src/plans-details/index.tsx index 38c535ff065a3..655f7c5cdf400 100644 --- a/packages/plans-grid/src/plans-details/index.tsx +++ b/packages/plans-grid/src/plans-details/index.tsx @@ -5,7 +5,7 @@ import { useI18n } from '@wordpress/react-i18n'; import classnames from 'classnames'; import * as React from 'react'; import { PLANS_STORE } from '../stores'; -import type { Plans } from '@automattic/data-stores'; +import type { Plans, PlansSelect } from '@automattic/data-stores'; import './style.scss'; @@ -21,21 +21,24 @@ type Props = { const PlansDetails: React.FunctionComponent< Props > = ( { onSelect, locale, billingPeriod } ) => { const { __, hasTranslation } = useI18n(); - const { supportedPlans, planProducts, features, featuresByType } = useSelect( ( select ) => { - const { getPlanProduct, getFeatures, getFeaturesByType, getSupportedPlans } = - select( PLANS_STORE ); - const supportedPlans = getSupportedPlans( locale ); - const planProducts = supportedPlans.map( ( plan ) => - getPlanProduct( plan.periodAgnosticSlug, billingPeriod ) - ); + const { supportedPlans, planProducts, features, featuresByType } = useSelect( + ( select ) => { + const { getPlanProduct, getFeatures, getFeaturesByType, getSupportedPlans }: PlansSelect = + select( PLANS_STORE ); + const supportedPlans = getSupportedPlans( locale ); + const planProducts = supportedPlans.map( ( plan ) => + getPlanProduct( plan.periodAgnosticSlug, billingPeriod ) + ); - return { - supportedPlans, - planProducts, - features: getFeatures( locale ), - featuresByType: getFeaturesByType( locale ), - }; - } ); + return { + supportedPlans, + planProducts, + features: getFeatures( locale ), + featuresByType: getFeaturesByType( locale ), + }; + }, + [ locale, billingPeriod ] + ); const isLoading = ! supportedPlans?.length; const placeholderPlans = [ 1, 2, 3, 4, 5 ]; diff --git a/packages/plans-grid/src/plans-grid/index.tsx b/packages/plans-grid/src/plans-grid/index.tsx index 83fec1c991efd..32ef538bb7f85 100644 --- a/packages/plans-grid/src/plans-grid/index.tsx +++ b/packages/plans-grid/src/plans-grid/index.tsx @@ -15,7 +15,7 @@ import type { DisabledPlansMap, PopularBadgeVariation, } from '../plans-table/types'; -import type { DomainSuggestions, WPCOMFeatures, Plans } from '@automattic/data-stores'; +import type { DomainSuggestions, WPCOMFeatures, Plans, PlansSelect } from '@automattic/data-stores'; import './style.scss'; @@ -63,7 +63,10 @@ const PlansGrid: React.FunctionComponent< Props > = ( { const { __ } = useI18n(); const selectedPlanBillingPeriod = useSelect( - ( select ) => select( PLANS_STORE ).getPlanProductById( currentPlanProductId )?.billingPeriod + ( select ) => + ( select( PLANS_STORE ) as PlansSelect ).getPlanProductById( currentPlanProductId ) + ?.billingPeriod, + [ currentPlanProductId ] ); const [ billingPeriod, setBillingPeriod ] = React.useState< Plans.PlanBillingPeriod >( diff --git a/packages/plans-grid/src/plans-table/index.tsx b/packages/plans-grid/src/plans-table/index.tsx index 67c2d29a658e3..08ee9e10f2a17 100644 --- a/packages/plans-grid/src/plans-table/index.tsx +++ b/packages/plans-grid/src/plans-table/index.tsx @@ -10,7 +10,7 @@ import type { CustomTagLinesMap, DisabledPlansMap, } from './types'; -import type { DomainSuggestions, Plans } from '@automattic/data-stores'; +import type { DomainSuggestions, Plans, PlansSelect } from '@automattic/data-stores'; import './style.scss'; @@ -47,7 +47,10 @@ const PlansTable: React.FunctionComponent< Props > = ( { const [ allPlansExpanded, setAllPlansExpanded ] = useState( defaultAllPlansExpanded ); - const getPlanProduct = useSelect( ( select ) => select( PLANS_STORE ).getPlanProduct ); + const getPlanProduct = useSelect( + ( select ) => ( select( PLANS_STORE ) as PlansSelect ).getPlanProduct, + [] + ); return (
diff --git a/packages/plans-grid/src/plans-table/plan-item.tsx b/packages/plans-grid/src/plans-table/plan-item.tsx index f78c64ed670fa..babd0f95872b3 100644 --- a/packages/plans-grid/src/plans-table/plan-item.tsx +++ b/packages/plans-grid/src/plans-table/plan-item.tsx @@ -10,7 +10,7 @@ import * as React from 'react'; import PlansFeatureList from '../plans-feature-list'; import { PLANS_STORE } from '../stores'; import type { CTAVariation, PopularBadgeVariation } from './types'; -import type { DomainSuggestions, Plans } from '@automattic/data-stores'; +import type { DomainSuggestions, Plans, PlansSelect } from '@automattic/data-stores'; // TODO: remove when all needed core types are available /*#__PURE__*/ import '../types-patch'; @@ -84,8 +84,9 @@ const PlanItem: React.FunctionComponent< Props > = ( { const { __, hasTranslation } = useI18n(); const locale = useLocale(); - const planProduct = useSelect( ( select ) => - select( PLANS_STORE ).getPlanProduct( slug, billingPeriod ) + const planProduct = useSelect( + ( select ) => ( select( PLANS_STORE ) as PlansSelect ).getPlanProduct( slug, billingPeriod ), + [ slug, billingPeriod ] ); const [ isOpenInternalState, setIsOpenInternalState ] = React.useState( false ); diff --git a/packages/search/package.json b/packages/search/package.json index e444ef7c0163b..c9ac54b115865 100644 --- a/packages/search/package.json +++ b/packages/search/package.json @@ -29,11 +29,11 @@ "dependencies": { "@automattic/typography": "workspace:^", "@babel/runtime": "^7.17.2", - "@wordpress/base-styles": "^4.7.0", - "@wordpress/components": "^19.15.0", - "@wordpress/compose": "^5.7.0", - "@wordpress/icons": "^9.0.0", - "@wordpress/react-i18n": "^3.7.0", + "@wordpress/base-styles": "^4.13.0", + "@wordpress/components": "^22.1.0", + "@wordpress/compose": "^5.20.0", + "@wordpress/icons": "^9.13.0", + "@wordpress/react-i18n": "^3.20.0", "classnames": "^2.3.1", "fuse.js": "^6.6.2", "lodash": "^4.17.21", @@ -54,8 +54,8 @@ "@testing-library/jest-dom": "^5.16.4", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.2.5", - "@wordpress/data": "^6.9.0", - "@wordpress/is-shallow-equal": "^4.9.0", + "@wordpress/data": "^7.6.0", + "@wordpress/is-shallow-equal": "^4.22.0", "react": "^17.0.2", "react-dom": "^17.0.2", "reakit-utils": "^0.15.1", diff --git a/packages/site-picker/package.json b/packages/site-picker/package.json index e10b2df04d30e..a94a6ab0e7a34 100644 --- a/packages/site-picker/package.json +++ b/packages/site-picker/package.json @@ -24,13 +24,13 @@ "bugs": "https://github.com/Automattic/wp-calypso/issues", "dependencies": { "@automattic/tour-kit": "workspace:^", - "@wordpress/dom": "^3.9.0", - "@wordpress/i18n": "^4.9.0", - "@wordpress/icons": "^9.0.0", + "@wordpress/dom": "^3.22.0", + "@wordpress/i18n": "^4.22.0", + "@wordpress/icons": "^9.13.0", "classnames": "^2.3.1" }, "peerDependencies": { - "@wordpress/data": "^6.1.5", + "@wordpress/data": "^7.6.0", "react": "^17.0.2", "react-dom": "^17.0.2", "reakit-utils": "^0.15.1", diff --git a/packages/sites/package.json b/packages/sites/package.json index d9285c75022f3..2519e772b7744 100644 --- a/packages/sites/package.json +++ b/packages/sites/package.json @@ -23,7 +23,7 @@ }, "bugs": "https://github.com/Automattic/wp-calypso/issues", "peerDependencies": { - "@wordpress/data": "^6.1.5", + "@wordpress/data": "^7.6.0", "react": "^17.0.2", "react-dom": "^17.0.2", "reakit-utils": "^0.15.1", diff --git a/packages/social-previews/package.json b/packages/social-previews/package.json index 87a6b6d354f39..415dcb6c664c7 100644 --- a/packages/social-previews/package.json +++ b/packages/social-previews/package.json @@ -38,8 +38,8 @@ }, "dependencies": { "@emotion/react": "^11.4.1", - "@wordpress/components": "^19.15.0", - "@wordpress/i18n": "^4.9.0", + "@wordpress/components": "^22.1.0", + "@wordpress/i18n": "^4.22.0", "classnames": "^2.3.1", "lodash": "^4.17.21", "moment": "^2.26.0", diff --git a/packages/social-previews/types.d.ts b/packages/social-previews/types.d.ts new file mode 100644 index 0000000000000..e2f78048ecb6a --- /dev/null +++ b/packages/social-previews/types.d.ts @@ -0,0 +1,21 @@ +declare module '@wordpress/notices' { + export type Status = 'error' | 'info' | 'success' | 'warning'; +} + +declare module '@wordpress/rich-text' { + interface Format { + type: string; + attributes?: Record< string, string > | undefined; + unregisteredAttributes?: Record< string, string > | undefined; + object?: boolean | undefined; + } + + export interface Value { + activeFormats?: readonly Format[] | undefined; + end?: number | undefined; + formats: ReadonlyArray< Format[] | undefined >; + replacements: ReadonlyArray< Format[] | undefined >; + start?: number | undefined; + text: string; + } +} diff --git a/packages/state-utils/package.json b/packages/state-utils/package.json index 5420204afff74..8f1ef55fc1ad9 100644 --- a/packages/state-utils/package.json +++ b/packages/state-utils/package.json @@ -30,8 +30,8 @@ "watch": "tsc --build ./tsconfig.json --watch" }, "dependencies": { - "@wordpress/is-shallow-equal": "^4.9.0", - "@wordpress/warning": "^2.9.0", + "@wordpress/is-shallow-equal": "^4.22.0", + "@wordpress/warning": "^2.22.0", "lodash": "^4.17.21", "redux": "^4.1.2", "redux-thunk": "^2.3.0", diff --git a/packages/subscriber/package.json b/packages/subscriber/package.json index 8d6256c09fb86..453e80150e7c4 100644 --- a/packages/subscriber/package.json +++ b/packages/subscriber/package.json @@ -33,14 +33,14 @@ "@automattic/viewport": "workspace:^", "@automattic/viewport-react": "workspace:^", "@popperjs/core": "^2.10.2", - "@wordpress/base-styles": "^4.5.0", - "@wordpress/components": "^19.11.0", - "@wordpress/dom": "^3.9.0", - "@wordpress/element": "^4.7.0", - "@wordpress/i18n": "^4.9.0", - "@wordpress/icons": "^9.0.0", - "@wordpress/primitives": "^3.7.0", - "@wordpress/react-i18n": "^3.7.0", + "@wordpress/base-styles": "^4.13.0", + "@wordpress/components": "^22.1.0", + "@wordpress/dom": "^3.22.0", + "@wordpress/element": "^4.20.0", + "@wordpress/i18n": "^4.22.0", + "@wordpress/icons": "^9.13.0", + "@wordpress/primitives": "^3.20.0", + "@wordpress/react-i18n": "^3.20.0", "classnames": "^2.3.1", "debug": "^4.3.4", "react-popper": "^2.2.5" @@ -51,7 +51,7 @@ "typescript": "^4.5.5" }, "peerDependencies": { - "@wordpress/data": "^6.1.5", + "@wordpress/data": "^7.6.0", "react": "^17.0.2", "react-dom": "^17.0.2", "reakit-utils": "^0.15.1", diff --git a/packages/subscriber/src/components/add-form/index.tsx b/packages/subscriber/src/components/add-form/index.tsx index bc733179fe6fb..9640f61cebccc 100644 --- a/packages/subscriber/src/components/add-form/index.tsx +++ b/packages/subscriber/src/components/add-form/index.tsx @@ -22,6 +22,7 @@ import { useInProgressState } from '../../hooks/use-in-progress-state'; import { RecordTrackEvents, useRecordAddFormEvents } from '../../hooks/use-record-add-form-events'; import { SUBSCRIBER_STORE } from '../../store'; import { tip } from './icon'; +import type { SubscriberSelect } from '@automattic/data-stores'; import './style.scss'; interface Props { @@ -42,7 +43,7 @@ interface Props { } export const AddSubscriberForm: FunctionComponent< Props > = ( props ) => { - const __ = useTranslate(); + const translate = useTranslate(); const HANDLED_ERROR = { IMPORT_LIMIT: 'subscriber_import_limit_reached', IMPORT_BLOCKED: 'blocked_import', @@ -55,7 +56,7 @@ export const AddSubscriberForm: FunctionComponent< Props > = ( props ) => { showSubtitle, showCsvUpload, showFormManualListLabel, - submitBtnName = __( 'Add subscribers' ), + submitBtnName = translate( 'Add subscribers' ), submitBtnAlwaysEnable, allowEmptyFormSubmit, manualListEmailInviting, @@ -75,9 +76,9 @@ export const AddSubscriberForm: FunctionComponent< Props > = ( props ) => { */ const emailControlMaxNum = 6; const emailControlPlaceholder = [ - __( 'sibling@example.com' ), - __( 'parents@example.com' ), - __( 'friend@example.com' ), + translate( 'sibling@example.com' ), + translate( 'parents@example.com' ), + translate( 'friend@example.com' ), ]; const inProgress = useInProgressState(); const prevInProgress = useRef( inProgress ); @@ -90,7 +91,10 @@ export const AddSubscriberForm: FunctionComponent< Props > = ( props ) => { const [ emailFormControls, setEmailFormControls ] = useState( emailControlPlaceholder ); const [ submitAttemptCount, setSubmitAttemptCount ] = useState( 0 ); const [ submitBtnReady, setIsSubmitBtnReady ] = useState( isSubmitButtonReady() ); - const importSelector = useSelect( ( s ) => s( SUBSCRIBER_STORE ).getImportSubscribersSelector() ); + const importSelector = useSelect( + ( s ) => ( s( SUBSCRIBER_STORE ) as SubscriberSelect ).getImportSubscribersSelector(), + [] + ); const [ formFileUploadElement ] = useState( createElement( FormFileUpload, { name: 'import', @@ -210,7 +214,7 @@ export const AddSubscriberForm: FunctionComponent< Props > = ( props ) => { currentEmailFormControlsNum === validEmailsNum ) { const controls = Array.from( emailFormControls ); - controls.push( __( 'Add another email' ) ); + controls.push( translate( 'Add another email' ) ); setEmailFormControls( controls ); } @@ -259,14 +263,14 @@ export const AddSubscriberForm: FunctionComponent< Props > = ( props ) => { switch ( error.code ) { case HANDLED_ERROR.IMPORT_LIMIT: return createInterpolateElement( - __( + translate( 'We couldn’t import your subscriber list as you’ve hit the 100 email limit for our free plan. The good news? You can upload a list of any size after upgrading to any paid plan. If you’d like to import a smaller list now, you can upload a different file.' ), { uploadBtn: formFileUploadElement } ); case HANDLED_ERROR.IMPORT_BLOCKED: - return __( + return translate( 'We ran into a security issue with your subscriber list. It’s nothing to worry about. If you reach out to our support team when you’ve finished setting things up, they’ll help resolve this for you.' ); @@ -284,7 +288,7 @@ export const AddSubscriberForm: FunctionComponent< Props > = ( props ) => { ! isSelectedFileValid && ( { createInterpolateElement( - __( + translate( 'Sorry, you can only upload CSV files right now. Most providers will let you export this from your settings. Select another file' ), { uploadBtn: formFileUploadElement } @@ -296,11 +300,11 @@ export const AddSubscriberForm: FunctionComponent< Props > = ( props ) => { function renderEmptyFormValidationMsg() { const validationMsg = showCsvUpload - ? __( + ? translate( "You'll need to add at least one email address " + 'or upload a CSV file of current subscribers to continue.' ) - : __( "You'll need to add at least one subscriber to continue." ); + : translate( "You'll need to add at least one subscriber to continue." ); return ( !! submitAttemptCount && @@ -315,7 +319,7 @@ export const AddSubscriberForm: FunctionComponent< Props > = ( props ) => { emailControlMaxNum === isValidEmails.filter( ( x ) => x ).length && ( - { __( 'Great start! You’ll be able to add more subscribers after setup.' ) } + { translate( 'Great start! You’ll be able to add more subscribers after setup.' ) } ) ); @@ -328,7 +332,7 @@ export const AddSubscriberForm: FunctionComponent< Props > = ( props ) => { { createInterpolateElement( sprintf( /* translators: the first string variable shows CTA button name */ - __( + translate( 'By clicking "%s", you represent that you\'ve obtained the appropriate consent to email each person. ' ), submitBtnName @@ -350,10 +354,12 @@ export const AddSubscriberForm: FunctionComponent< Props > = ( props ) => { function renderImportCsvLabel() { const ariaLabelMsg = isSiteOnFreePlan - ? __( + ? translate( 'Or bring your mailing list up to 100 emails from other newsletter services by uploading a CSV file.' ) - : __( 'Or bring your mailing list from other newsletter services by uploading a CSV file.' ); + : translate( + 'Or bring your mailing list from other newsletter services by uploading a CSV file.' + ); return ( isSelectedFileValid && @@ -361,10 +367,10 @@ export const AddSubscriberForm: FunctionComponent< Props > = ( props ) => {