From bf9d7e865b876962e77fbd297b557de4300d4249 Mon Sep 17 00:00:00 2001 From: Manzoor Wani Date: Thu, 16 Nov 2023 10:39:28 +0530 Subject: [PATCH] Get rid of `jetpack/publicize` store (#34111) * Move store sections to separate utility functions * Update consumer components * Get rid of lodash and refx deps * Add changelog * Update SIG settings type * Rename getImageGeneratorSettings back to getImageGeneratorPostSettings * Unify connection availability check * Add changelog * @wordpress/data isn't made to work well with TypeScript * Fix unit tests * Add unit tests --- pnpm-lock.yaml | 6 - .../update-remove-jetpack-publicize-store | 4 + .../js-packages/publicize-components/index.ts | 2 +- .../publicize-components/package.json | 2 - .../src/components/connection/index.js | 3 +- .../components/connection/test/index.test.js | 1 - .../src/components/form/index.js | 10 +- .../share-buttons/useShareButtonText.ts | 4 +- .../components/social-previews/mastodon.js | 2 +- .../src/components/social-previews/modal.js | 2 +- .../src/components/social-previews/twitter.js | 2 +- .../social-previews/useAvailableServices.js | 22 ++-- .../src/hooks/use-attached-media/index.js | 19 +-- .../hooks/use-image-generator-config/index.js | 25 ++-- .../src/hooks/use-publicize-config/index.js | 19 ++- .../hooks/use-social-media-message/index.js | 15 +-- .../publicize-components/src/store/actions.js | 82 ------------ .../src/store/controls.js | 16 --- .../publicize-components/src/store/effects.js | 18 --- .../publicize-components/src/store/index.js | 17 --- .../src/store/middlewares.js | 32 ----- .../publicize-components/src/store/reducer.js | 15 --- .../src/store/selectors.js | 124 ------------------ .../src/utils/get-attached-media.js | 11 ++ .../get-image-generator-post-settings.js | 11 ++ .../src/utils/get-jetpack-social-options.js | 15 +++ .../get-jetpack-social-post-already-shared.js | 15 +++ .../src/utils/get-share-message-max-length.js | 14 ++ .../src/utils/get-share-message.js | 20 +++ .../get-supported-additional-connections.js | 10 ++ .../publicize-components/src/utils/index.js | 11 ++ .../src/utils/is-publicize-enabled.js | 16 +++ .../src/utils/should-upload-attached-media.js | 10 ++ .../src/utils/test-utils.js | 56 ++++++++ .../src/utils/test/get-attached-media.js | 44 +++++++ .../test/get-image-generator-post-settings.js | 50 +++++++ .../utils/test/get-jetpack-social-options.js | 36 +++++ .../get-jetpack-social-post-already-shared.js | 40 ++++++ .../src/utils/test/get-share-message.js | 43 ++++++ .../src/utils/test/is-publicize-enabled.js | 40 ++++++ .../test/should-upload-attached-media.js | 44 +++++++ .../utils/test/toggle-publicize-feature.js | 32 +++++ .../src/utils/toggle-publicize-feature.js | 16 +++ .../publicize-components/src/utils/types.ts | 20 +++ .../update-remove-jetpack-publicize-store | 4 + .../publicize/src/class-publicize-base.php | 34 +++++ .../update-remove-jetpack-publicize-store | 4 + .../jetpack/class.jetpack-gutenberg.php | 4 +- .../update-remove-jetpack-publicize-store | 4 + .../social/src/class-jetpack-social.php | 7 +- .../js/components/instagram-notice/index.jsx | 28 ++-- .../js/components/publicize-panel/index.jsx | 10 +- 52 files changed, 680 insertions(+), 411 deletions(-) create mode 100644 projects/js-packages/publicize-components/changelog/update-remove-jetpack-publicize-store delete mode 100644 projects/js-packages/publicize-components/src/store/actions.js delete mode 100644 projects/js-packages/publicize-components/src/store/controls.js delete mode 100644 projects/js-packages/publicize-components/src/store/effects.js delete mode 100644 projects/js-packages/publicize-components/src/store/index.js delete mode 100644 projects/js-packages/publicize-components/src/store/middlewares.js delete mode 100644 projects/js-packages/publicize-components/src/store/reducer.js delete mode 100644 projects/js-packages/publicize-components/src/store/selectors.js create mode 100644 projects/js-packages/publicize-components/src/utils/get-attached-media.js create mode 100644 projects/js-packages/publicize-components/src/utils/get-image-generator-post-settings.js create mode 100644 projects/js-packages/publicize-components/src/utils/get-jetpack-social-options.js create mode 100644 projects/js-packages/publicize-components/src/utils/get-jetpack-social-post-already-shared.js create mode 100644 projects/js-packages/publicize-components/src/utils/get-share-message-max-length.js create mode 100644 projects/js-packages/publicize-components/src/utils/get-share-message.js create mode 100644 projects/js-packages/publicize-components/src/utils/get-supported-additional-connections.js create mode 100644 projects/js-packages/publicize-components/src/utils/index.js create mode 100644 projects/js-packages/publicize-components/src/utils/is-publicize-enabled.js create mode 100644 projects/js-packages/publicize-components/src/utils/should-upload-attached-media.js create mode 100644 projects/js-packages/publicize-components/src/utils/test-utils.js create mode 100644 projects/js-packages/publicize-components/src/utils/test/get-attached-media.js create mode 100644 projects/js-packages/publicize-components/src/utils/test/get-image-generator-post-settings.js create mode 100644 projects/js-packages/publicize-components/src/utils/test/get-jetpack-social-options.js create mode 100644 projects/js-packages/publicize-components/src/utils/test/get-jetpack-social-post-already-shared.js create mode 100644 projects/js-packages/publicize-components/src/utils/test/get-share-message.js create mode 100644 projects/js-packages/publicize-components/src/utils/test/is-publicize-enabled.js create mode 100644 projects/js-packages/publicize-components/src/utils/test/should-upload-attached-media.js create mode 100644 projects/js-packages/publicize-components/src/utils/test/toggle-publicize-feature.js create mode 100644 projects/js-packages/publicize-components/src/utils/toggle-publicize-feature.js create mode 100644 projects/js-packages/publicize-components/src/utils/types.ts create mode 100644 projects/packages/publicize/changelog/update-remove-jetpack-publicize-store create mode 100644 projects/plugins/jetpack/changelog/update-remove-jetpack-publicize-store create mode 100644 projects/plugins/social/changelog/update-remove-jetpack-publicize-store diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 05b1fb0fd06a6..aecf0f858d90e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -849,18 +849,12 @@ importers: classnames: specifier: 2.3.2 version: 2.3.2 - lodash: - specifier: 4.17.21 - version: 4.17.21 prop-types: specifier: 15.8.1 version: 15.8.1 react-page-visibility: specifier: 7.0.0 version: 7.0.0(react@18.2.0) - refx: - specifier: 3.1.1 - version: 3.1.1 rememo: specifier: 4.0.1 version: 4.0.1 diff --git a/projects/js-packages/publicize-components/changelog/update-remove-jetpack-publicize-store b/projects/js-packages/publicize-components/changelog/update-remove-jetpack-publicize-store new file mode 100644 index 0000000000000..1767a316a1499 --- /dev/null +++ b/projects/js-packages/publicize-components/changelog/update-remove-jetpack-publicize-store @@ -0,0 +1,4 @@ +Significance: patch +Type: removed + +Removed jetpack/publicize store diff --git a/projects/js-packages/publicize-components/index.ts b/projects/js-packages/publicize-components/index.ts index 061990860c32f..c96c645640d3a 100644 --- a/projects/js-packages/publicize-components/index.ts +++ b/projects/js-packages/publicize-components/index.ts @@ -1,7 +1,6 @@ //TODO: Work out a more explicit way of initialising the store //where it's needed. It's not clear if we'll always want the //store for the components, but at the moment they're tied. -import './src/store'; import './src/social-store'; export { default as Connection } from './src/components/connection'; @@ -26,6 +25,7 @@ export { default as useSharePost } from './src/hooks/use-share-post'; export { default as useDismissNotice } from './src/hooks/use-dismiss-notice'; export * from './src/social-store'; +export * from './src/utils'; export * from './src/components/share-post'; export * from './src/hooks/use-saving-post'; export * from './src/components/share-buttons'; diff --git a/projects/js-packages/publicize-components/package.json b/projects/js-packages/publicize-components/package.json index 3d32e7ec69ea0..be3aa22fe399a 100644 --- a/projects/js-packages/publicize-components/package.json +++ b/projects/js-packages/publicize-components/package.json @@ -39,10 +39,8 @@ "@wordpress/icons": "9.36.0", "@wordpress/notices": "4.13.0", "classnames": "2.3.2", - "lodash": "4.17.21", "prop-types": "15.8.1", "react-page-visibility": "7.0.0", - "refx": "3.1.1", "rememo": "4.0.1" }, "devDependencies": { diff --git a/projects/js-packages/publicize-components/src/components/connection/index.js b/projects/js-packages/publicize-components/src/components/connection/index.js index 848db5de349e9..fbc3878fb5d45 100644 --- a/projects/js-packages/publicize-components/src/components/connection/index.js +++ b/projects/js-packages/publicize-components/src/components/connection/index.js @@ -10,7 +10,6 @@ import { Notice, ExternalLink } from '@wordpress/components'; import { withSelect } from '@wordpress/data'; import { Component } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; -import { includes } from 'lodash'; import { SOCIAL_STORE_ID } from '../../social-store'; import ConnectionToggle from '../connection-toggle'; import componentStyles from '../styles.module.scss'; @@ -47,7 +46,7 @@ class PublicizeConnection extends Component { * * @returns {boolean} True if connection must be reauthenticated. */ - connectionNeedsReauth = () => includes( this.props.mustReauthConnections, this.props.name ); + connectionNeedsReauth = () => this.props.mustReauthConnections.includes( this.props.name ); onConnectionChange = () => { const { id } = this.props; diff --git a/projects/js-packages/publicize-components/src/components/connection/test/index.test.js b/projects/js-packages/publicize-components/src/components/connection/test/index.test.js index 7093f72fdb9b7..cc53e121d52f2 100644 --- a/projects/js-packages/publicize-components/src/components/connection/test/index.test.js +++ b/projects/js-packages/publicize-components/src/components/connection/test/index.test.js @@ -2,7 +2,6 @@ import { jest } from '@jest/globals'; import { render, renderHook, screen } from '@testing-library/react'; import { useSelect } from '@wordpress/data'; import React from 'react'; -import '../../../store'; import { SOCIAL_STORE_ID } from '../../../social-store'; import PublicizeConnection from '../index'; diff --git a/projects/js-packages/publicize-components/src/components/form/index.js b/projects/js-packages/publicize-components/src/components/form/index.js index 8e3b6984a71f9..9bc97aa3b47a4 100644 --- a/projects/js-packages/publicize-components/src/components/form/index.js +++ b/projects/js-packages/publicize-components/src/components/form/index.js @@ -22,7 +22,8 @@ import useRefreshAutoConversionSettings from '../../hooks/use-refresh-auto-conve import useRefreshConnections from '../../hooks/use-refresh-connections'; import useSocialMediaConnections from '../../hooks/use-social-media-connections'; import useSocialMediaMessage from '../../hooks/use-social-media-message'; -import { SOCIAL_STORE_ID } from '../../social-store'; +import { CONNECTION_SERVICE_INSTAGRAM_BUSINESS, SOCIAL_STORE_ID } from '../../social-store'; +import { getSupportedAdditionalConnections } from '../../utils'; import PublicizeConnection from '../connection'; import MediaSection from '../media-section'; import MessageBoxControl from '../message-box-control'; @@ -30,7 +31,6 @@ import Notice from '../notice'; import PublicizeSettingsButton from '../settings-button'; import styles from './styles.module.scss'; -const PUBLICIZE_STORE_ID = 'jetpack/publicize'; const MONTH_IN_SECONDS = 30 * 24 * 60 * 60; const checkConnectionCode = ( connection, code ) => @@ -69,17 +69,13 @@ export default function PublicizeForm( { const { isEnabled: isSocialImageGeneratorEnabledForPost } = useImageGeneratorConfig(); const { dismissNotice, shouldShowNotice, NOTICES } = useDismissNotice(); - const { isInstagramConnectionSupported } = useSelect( select => ( { - isInstagramConnectionSupported: select( PUBLICIZE_STORE_ID ).isInstagramConnectionSupported(), - } ) ); - const hasInstagramConnection = connections.some( connection => connection.service_name === 'instagram-business' ); const shouldShowInstagramNotice = ! hasInstagramConnection && - isInstagramConnectionSupported && + getSupportedAdditionalConnections().includes( CONNECTION_SERVICE_INSTAGRAM_BUSINESS ) && shouldShowNotice( NOTICES.instagram ); const onDismissInstagramNotice = useCallback( () => { diff --git a/projects/js-packages/publicize-components/src/components/share-buttons/useShareButtonText.ts b/projects/js-packages/publicize-components/src/components/share-buttons/useShareButtonText.ts index 8f78af8330d29..af28a7a2b4dc0 100644 --- a/projects/js-packages/publicize-components/src/components/share-buttons/useShareButtonText.ts +++ b/projects/js-packages/publicize-components/src/components/share-buttons/useShareButtonText.ts @@ -1,5 +1,6 @@ import { useSelect } from '@wordpress/data'; import { useCallback } from '@wordpress/element'; +import { getShareMessage } from '../../utils'; /** * Prepares the text to share. @@ -15,8 +16,7 @@ export function useShareButtonText() { return { link: getEditedPostAttribute( 'link' ), message: - // eslint-disable-next-line @typescript-eslint/no-explicit-any - ( select( 'jetpack/publicize' ) as any ).getShareMessage() || + getShareMessage() || getEditedPostAttribute( 'meta' )?.jetpack_seo_html_title || getEditedPostAttribute( 'title' ), }; diff --git a/projects/js-packages/publicize-components/src/components/social-previews/mastodon.js b/projects/js-packages/publicize-components/src/components/social-previews/mastodon.js index 8460483e55d94..0f102072437cb 100644 --- a/projects/js-packages/publicize-components/src/components/social-previews/mastodon.js +++ b/projects/js-packages/publicize-components/src/components/social-previews/mastodon.js @@ -3,7 +3,7 @@ import { useSelect } from '@wordpress/data'; import { decodeEntities } from '@wordpress/html-entities'; import useSocialMediaMessage from '../../hooks/use-social-media-message'; import { SOCIAL_STORE_ID, CONNECTION_SERVICE_MASTODON } from '../../social-store'; -import { shouldUploadAttachedMedia } from '../../store/selectors'; +import { shouldUploadAttachedMedia } from '../../utils'; const MastodonPreview = props => { const { message } = useSocialMediaMessage(); diff --git a/projects/js-packages/publicize-components/src/components/social-previews/modal.js b/projects/js-packages/publicize-components/src/components/social-previews/modal.js index ed84f13f40260..bdedc0a97241a 100644 --- a/projects/js-packages/publicize-components/src/components/social-previews/modal.js +++ b/projects/js-packages/publicize-components/src/components/social-previews/modal.js @@ -12,7 +12,7 @@ import { getAttachedMedia, getImageGeneratorPostSettings, shouldUploadAttachedMedia, -} from '../../store/selectors'; +} from '../../utils'; import { getSigImageUrl } from '../generated-image-preview/utils'; import { useAvailableSerivces } from './useAvailableServices'; import { getMediaSourceUrl } from './utils'; diff --git a/projects/js-packages/publicize-components/src/components/social-previews/twitter.js b/projects/js-packages/publicize-components/src/components/social-previews/twitter.js index 6c1b0c4cacb57..613f6a0beb196 100644 --- a/projects/js-packages/publicize-components/src/components/social-previews/twitter.js +++ b/projects/js-packages/publicize-components/src/components/social-previews/twitter.js @@ -2,6 +2,7 @@ import { TwitterPreviews } from '@automattic/social-previews'; import { useSelect } from '@wordpress/data'; import React from 'react'; import { SOCIAL_STORE_ID, CONNECTION_SERVICE_TWITTER } from '../../social-store'; +import { getShareMessage } from '../../utils'; /** * The twitter tab component. @@ -17,7 +18,6 @@ import { SOCIAL_STORE_ID, CONNECTION_SERVICE_TWITTER } from '../../social-store' function Twitter( { title, description, image, url, media } ) { const tweets = useSelect( select => { - const { getShareMessage } = select( 'jetpack/publicize' ); const { displayName: name, profileImage, diff --git a/projects/js-packages/publicize-components/src/components/social-previews/useAvailableServices.js b/projects/js-packages/publicize-components/src/components/social-previews/useAvailableServices.js index acd224ac6dedf..e759be984da96 100644 --- a/projects/js-packages/publicize-components/src/components/social-previews/useAvailableServices.js +++ b/projects/js-packages/publicize-components/src/components/social-previews/useAvailableServices.js @@ -1,7 +1,12 @@ import { SocialServiceIcon } from '@automattic/jetpack-components'; -import { useSelect } from '@wordpress/data'; import { __ } from '@wordpress/i18n'; import React, { useMemo } from 'react'; +import { + CONNECTION_SERVICE_INSTAGRAM_BUSINESS, + CONNECTION_SERVICE_MASTODON, + CONNECTION_SERVICE_NEXTDOOR, +} from '../../social-store'; +import { getSupportedAdditionalConnections } from '../../utils'; import FacebookPreview from './facebook'; import GoogleSearch from './google-search'; import { Instagram } from './instagram'; @@ -17,15 +22,12 @@ import Twitter from './twitter'; * @returns {Array<{title: string, icon: React.Component, name: string, preview: React.Component}>} The list of available services. */ export function useAvailableSerivces() { - const { isInstagramSupported, isMastodonSupported, isNextdoorSupported } = useSelect( select => { - const store = select( 'jetpack/publicize' ); - - return { - isInstagramSupported: store.isInstagramConnectionSupported(), - isMastodonSupported: store.isMastodonConnectionSupported(), - isNextdoorSupported: store.isNextdoorConnectionSupported(), - }; - } ); + const additionalConnections = getSupportedAdditionalConnections(); + const isInstagramSupported = additionalConnections.includes( + CONNECTION_SERVICE_INSTAGRAM_BUSINESS + ); + const isMastodonSupported = additionalConnections.includes( CONNECTION_SERVICE_MASTODON ); + const isNextdoorSupported = additionalConnections.includes( CONNECTION_SERVICE_NEXTDOOR ); return useMemo( () => diff --git a/projects/js-packages/publicize-components/src/hooks/use-attached-media/index.js b/projects/js-packages/publicize-components/src/hooks/use-attached-media/index.js index 4ebe4d2e40cac..336f624f294b6 100644 --- a/projects/js-packages/publicize-components/src/hooks/use-attached-media/index.js +++ b/projects/js-packages/publicize-components/src/hooks/use-attached-media/index.js @@ -1,8 +1,7 @@ -import { useSelect, useDispatch } from '@wordpress/data'; +import { useDispatch } from '@wordpress/data'; import { store as editorStore } from '@wordpress/editor'; import { useCallback } from '@wordpress/element'; - -const PUBLICIZE_STORE = 'jetpack/publicize'; +import { getAttachedMedia, getJetpackSocialOptions, shouldUploadAttachedMedia } from '../../utils'; /** * @typedef {object} AttachedMediaHook @@ -20,26 +19,20 @@ const PUBLICIZE_STORE = 'jetpack/publicize'; export default function useAttachedMedia() { const { editPost } = useDispatch( editorStore ); - const { shouldUploadAttachedMedia, attachedMedia, currentOptions } = useSelect( select => ( { - shouldUploadAttachedMedia: select( PUBLICIZE_STORE ).shouldUploadAttachedMedia(), - attachedMedia: select( PUBLICIZE_STORE ).getAttachedMedia(), - currentOptions: select( PUBLICIZE_STORE ).getJetpackSocialOptions(), - } ) ); - const updateJetpackSocialOptions = useCallback( ( key, value ) => { editPost( { meta: { - jetpack_social_options: { ...currentOptions, [ key ]: value }, + jetpack_social_options: { ...getJetpackSocialOptions(), [ key ]: value }, }, } ); }, - [ currentOptions, editPost ] + [ editPost ] ); return { - attachedMedia, - shouldUploadAttachedMedia, + attachedMedia: getAttachedMedia(), + shouldUploadAttachedMedia: shouldUploadAttachedMedia(), updateAttachedMedia: media => updateJetpackSocialOptions( 'attached_media', media ), updateShouldUploadAttachedMedia: option => updateJetpackSocialOptions( 'should_upload_attached_media', option ), diff --git a/projects/js-packages/publicize-components/src/hooks/use-image-generator-config/index.js b/projects/js-packages/publicize-components/src/hooks/use-image-generator-config/index.js index f063b80297aba..8e80a3baf914b 100644 --- a/projects/js-packages/publicize-components/src/hooks/use-image-generator-config/index.js +++ b/projects/js-packages/publicize-components/src/hooks/use-image-generator-config/index.js @@ -1,8 +1,7 @@ import { useSelect, useDispatch } from '@wordpress/data'; import { store as editorStore } from '@wordpress/editor'; import { useCallback } from '@wordpress/element'; - -const PUBLICIZE_STORE_ID = 'jetpack/publicize'; +import { getJetpackSocialOptions, getImageGeneratorPostSettings } from '../../utils'; const getCurrentSettings = ( sigSettings, isPostPublished ) => ( { isEnabled: sigSettings?.enabled ?? ! isPostPublished, @@ -34,11 +33,6 @@ const getCurrentSettings = ( sigSettings, isPostPublished ) => ( { export default function useImageGeneratorConfig() { const { editPost } = useDispatch( editorStore ); - const { postSettings, currentOptions } = useSelect( select => ( { - postSettings: select( PUBLICIZE_STORE_ID ).getImageGeneratorPostSettings(), - currentOptions: select( PUBLICIZE_STORE_ID ).getJetpackSocialOptions(), - } ) ); - const { isPostPublished } = useSelect( select => ( { isPostPublished: select( editorStore ).isCurrentPostPublished(), } ) ); @@ -47,31 +41,34 @@ export default function useImageGeneratorConfig() { settings => { editPost( { meta: { - jetpack_social_options: { ...currentOptions, image_generator_settings: settings }, + jetpack_social_options: { + ...getJetpackSocialOptions(), + image_generator_settings: settings, + }, }, } ); }, - [ currentOptions, editPost ] + [ editPost ] ); const updateProperty = useCallback( ( key, value ) => { - const settings = { ...postSettings, [ key ]: value }; + const settings = { ...getImageGeneratorPostSettings(), [ key ]: value }; _commitPostUpdate( settings ); }, - [ postSettings, _commitPostUpdate ] + [ _commitPostUpdate ] ); const updateSettings = useCallback( settings => { - const newSettings = { ...postSettings, ...settings }; + const newSettings = { ...getImageGeneratorPostSettings(), ...settings }; _commitPostUpdate( newSettings ); }, - [ postSettings, _commitPostUpdate ] + [ _commitPostUpdate ] ); return { - ...getCurrentSettings( currentOptions?.image_generator_settings, isPostPublished ), + ...getCurrentSettings( getJetpackSocialOptions().image_generator_settings, isPostPublished ), setIsEnabled: value => updateProperty( 'enabled', value ), setToken: value => updateProperty( 'token', value ), updateSettings, diff --git a/projects/js-packages/publicize-components/src/hooks/use-publicize-config/index.js b/projects/js-packages/publicize-components/src/hooks/use-publicize-config/index.js index a9e1877f0f1c7..8025156f5ce9d 100644 --- a/projects/js-packages/publicize-components/src/hooks/use-publicize-config/index.js +++ b/projects/js-packages/publicize-components/src/hooks/use-publicize-config/index.js @@ -4,8 +4,13 @@ import { getJetpackData, getSiteFragment, } from '@automattic/jetpack-shared-extension-utils'; -import { useSelect, useDispatch } from '@wordpress/data'; +import { useSelect } from '@wordpress/data'; import { store as editorStore } from '@wordpress/editor'; +import { + isPublicizeEnabled as isPublicizeFeatureEnabled, + getJetpackSocialPostAlreadyShared, + togglePublicizeFeature, +} from '../../utils'; const republicizeFeatureName = 'republicize'; @@ -17,16 +22,13 @@ const republicizeFeatureName = 'republicize'; * for toggling support for the current post. */ export default function usePublicizeConfig() { - const { togglePublicizeFeature } = useDispatch( 'jetpack/publicize' ); const sharesData = getJetpackData()?.social?.sharesData ?? {}; const isShareLimitEnabled = sharesData.is_share_limit_enabled; const isRePublicizeFeatureAvailable = getJetpackExtensionAvailability( republicizeFeatureName )?.available || isShareLimitEnabled; const isPostPublished = useSelect( select => select( editorStore ).isCurrentPostPublished(), [] ); - const isPostAlreadyShared = useSelect( - select => select( 'jetpack/publicize' ).getJetpackSocialPostAlreadyShared(), - [] - ); + const isPostAlreadyShared = getJetpackSocialPostAlreadyShared(); + const connectionsRootUrl = getJetpackData()?.social?.publicizeConnectionsUrl ?? 'https://wordpress.com/marketing/connections/'; @@ -37,10 +39,7 @@ export default function usePublicizeConfig() { * and usually is handled from the UI (main toggle control), * dispathicng the togglePublicizeFeature() action (jetpack/publicize). */ - const isPublicizeEnabledMeta = useSelect( - select => select( 'jetpack/publicize' ).getFeatureEnableState(), - [] - ); + const isPublicizeEnabledMeta = isPublicizeFeatureEnabled(); /* * isRePublicizeUpgradableViaUpsell: diff --git a/projects/js-packages/publicize-components/src/hooks/use-social-media-message/index.js b/projects/js-packages/publicize-components/src/hooks/use-social-media-message/index.js index 2c660ccd99e73..92f0017ec97a3 100644 --- a/projects/js-packages/publicize-components/src/hooks/use-social-media-message/index.js +++ b/projects/js-packages/publicize-components/src/hooks/use-social-media-message/index.js @@ -1,5 +1,6 @@ -import { useSelect, useDispatch } from '@wordpress/data'; +import { useDispatch } from '@wordpress/data'; import { store as editorStore } from '@wordpress/editor'; +import { getShareMessage, getShareMessageMaxLength } from '../../utils'; /** * @typedef {object} MessageHook @@ -16,17 +17,9 @@ import { store as editorStore } from '@wordpress/editor'; export default function useSocialMediaMessage() { const { editPost } = useDispatch( editorStore ); - const { message, maxLength } = useSelect( - select => ( { - message: select( 'jetpack/publicize' ).getShareMessage(), - maxLength: select( 'jetpack/publicize' ).getShareMessageMaxLength(), - } ), - [] - ); - return { - message, - maxLength, + message: getShareMessage(), + maxLength: getShareMessageMaxLength(), updateMessage: function ( text ) { editPost( { meta: { diff --git a/projects/js-packages/publicize-components/src/store/actions.js b/projects/js-packages/publicize-components/src/store/actions.js deleted file mode 100644 index 3a95a73a23085..0000000000000 --- a/projects/js-packages/publicize-components/src/store/actions.js +++ /dev/null @@ -1,82 +0,0 @@ -import { select } from '@wordpress/data'; - -/** - * Returns an action object used in signalling that - * we're toggling the post share feature. - * - * @returns {object} Action object. - */ -export function togglePublicizeFeature() { - return { - type: 'TOGGLE_PUBLICIZE_FEATURE', - }; -} - -/** - * Returns an action object used in signalling that - * we're initiating a fetch request to the REST API. - * - * @param {string} path - API endpoint path. - * @returns {object} Action object. - */ -export function fetchFromAPI( path ) { - return { - type: 'FETCH_FROM_API', - path, - }; -} - -/** - * Returns an action object used in signalling that we're refreshing - * the tweets that have been parsed out of the content. - * - * @returns {object} Action object. - */ -export function refreshTweets() { - return { - type: 'REFRESH_TWEETS', - }; -} - -/** - * Returns an action object used in signalling that tweets have been refreshed, - * and the state will be updated. - * - * @param {Array} tweets - The array of tweet objects returned by the parser. - * @returns {object} Action object. - */ -export function setTweets( tweets ) { - return { - type: 'SET_TWEETS', - tweets, - }; -} - -/** - * Returns an action object used in signalling that we're fetching Twitter Cards. - * - * @param {Array} urls - An array of URLs to fetch. - * @returns {object} Action object. - */ -export function getTwitterCards( urls ) { - const { twitterCardIsCached } = select( 'jetpack/publicize' ); - - return { - type: 'GET_TWITTER_CARDS', - urls: urls.filter( url => ! twitterCardIsCached( url ) ), - }; -} - -/** - * Returns an action object used in signalling that Twitter Cards have been fetched - * and the state will be updated. - * - * @param {Array} cards - The array of card object returned by the server. - * @returns {object} Action object. - */ -export function setTwitterCards( cards ) { - return { - type: 'SET_TWITTER_CARDS', - cards, - }; -} diff --git a/projects/js-packages/publicize-components/src/store/controls.js b/projects/js-packages/publicize-components/src/store/controls.js deleted file mode 100644 index 3c9d451ee259a..0000000000000 --- a/projects/js-packages/publicize-components/src/store/controls.js +++ /dev/null @@ -1,16 +0,0 @@ -import apiFetch from '@wordpress/api-fetch'; - -/** - * Trigger an API Fetch request. - * - * @param {object} action - Action Object. - * @param {object} action.path - Action path. - * @returns {Promise} Fetch request promise. - */ -const fetchFromApi = ( { path } ) => { - return apiFetch( { path } ); -}; - -export default { - FETCH_FROM_API: fetchFromApi, -}; diff --git a/projects/js-packages/publicize-components/src/store/effects.js b/projects/js-packages/publicize-components/src/store/effects.js deleted file mode 100644 index f6068bc15df71..0000000000000 --- a/projects/js-packages/publicize-components/src/store/effects.js +++ /dev/null @@ -1,18 +0,0 @@ -import { dispatch, select } from '@wordpress/data'; -import { store as editorStore } from '@wordpress/editor'; - -/** - * Effect handler to toggle and store Post Share enable feature state. - * - * @returns {object} Updateting jetpack_publicize_feature_enabled post meta action. - */ -export async function togglePublicizeFeature() { - const isPublicizeFeatureEnabled = select( 'jetpack/publicize' ).getFeatureEnableState(); - return dispatch( editorStore ).editPost( { - meta: { jetpack_publicize_feature_enabled: ! isPublicizeFeatureEnabled }, - } ); -} - -export default { - TOGGLE_PUBLICIZE_FEATURE: togglePublicizeFeature, -}; diff --git a/projects/js-packages/publicize-components/src/store/index.js b/projects/js-packages/publicize-components/src/store/index.js deleted file mode 100644 index a081f4a73b1a2..0000000000000 --- a/projects/js-packages/publicize-components/src/store/index.js +++ /dev/null @@ -1,17 +0,0 @@ -import { registerStore } from '@wordpress/data'; -import * as actions from './actions'; -import controls from './controls'; -import applyMiddlewares from './middlewares'; -import reducer from './reducer'; -import * as selectors from './selectors'; - -const store = registerStore( 'jetpack/publicize', { - actions, - controls, - reducer, - selectors, -} ); - -applyMiddlewares( store ); - -export default store; diff --git a/projects/js-packages/publicize-components/src/store/middlewares.js b/projects/js-packages/publicize-components/src/store/middlewares.js deleted file mode 100644 index 3ea96785288e4..0000000000000 --- a/projects/js-packages/publicize-components/src/store/middlewares.js +++ /dev/null @@ -1,32 +0,0 @@ -import { flowRight } from 'lodash'; -import refx from 'refx'; -import effects from './effects'; - -/** - * Applies the custom middlewares used specifically in the Publicize extension. - * - * @param {object} store - Store Object. - * @returns {object} Update Store Object. - */ -export default function applyMiddlewares( store ) { - const middlewares = [ refx( effects ) ]; - - let enhancedDispatch = () => { - throw new Error( - 'Dispatching while constructing your middleware is not allowed. ' + - 'Other middleware would not be applied to this dispatch.' - ); - }; - let chain = []; - - const middlewareAPI = { - getState: store.getState, - dispatch: ( ...args ) => enhancedDispatch( ...args ), - }; - chain = middlewares.map( middleware => middleware( middlewareAPI ) ); - enhancedDispatch = flowRight( ...chain )( store.dispatch ); - - store.dispatch = enhancedDispatch; - - return store; -} diff --git a/projects/js-packages/publicize-components/src/store/reducer.js b/projects/js-packages/publicize-components/src/store/reducer.js deleted file mode 100644 index ae9c6be2f4740..0000000000000 --- a/projects/js-packages/publicize-components/src/store/reducer.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Reducer managing Publicize connection test results. - * - * @param {object} state - Current state. - * @param {object} action - Dispatched action. - * @returns {object} Updated state. - */ -export default function ( state = {}, action ) { - switch ( action.type ) { - case 'TOGGLE_PUBLICIZE_FEATURE': - return state; - } - - return state; -} diff --git a/projects/js-packages/publicize-components/src/store/selectors.js b/projects/js-packages/publicize-components/src/store/selectors.js deleted file mode 100644 index bcfadd5f308c6..0000000000000 --- a/projects/js-packages/publicize-components/src/store/selectors.js +++ /dev/null @@ -1,124 +0,0 @@ -import { getJetpackData } from '@automattic/jetpack-shared-extension-utils'; -import { select } from '@wordpress/data'; -import { store as editorStore } from '@wordpress/editor'; -import { get } from 'lodash'; - -// Links and media attached to tweets take up 24 characters each. -const ATTACHMENT_MESSAGE_PADDING = 24; - -// The maximum length is 280 characters, but there'll always be a URL attached (plus a space). -const MAXIMUM_MESSAGE_LENGTH = 280 - ATTACHMENT_MESSAGE_PADDING - 1; - -/** - * Gets the message that will be used hen sharing this post. - * - * @returns {string} The share message. - */ -export function getShareMessage() { - const { getEditedPostAttribute } = select( 'core/editor' ); - const meta = getEditedPostAttribute( 'meta' ); - const message = get( meta, [ 'jetpack_publicize_message' ], '' ); - - if ( message ) { - return message.substr( 0, getShareMessageMaxLength() ); - } - - return ''; -} - -/** - * Get the maximum length that a share message can be. - * - * @returns {number} The maximum length of a share message. - */ -export function getShareMessageMaxLength() { - return MAXIMUM_MESSAGE_LENGTH; -} - -/** - * Return True if Publicize Feature is enabled. - * Otherwise, return False. - * - * @returns {boolean} Whether or not the publicize feature is enabled. - */ -export function getFeatureEnableState() { - const { getEditedPostAttribute } = select( editorStore ); - const meta = getEditedPostAttribute( 'meta' ); - return get( meta, [ 'jetpack_publicize_feature_enabled' ], true ); -} - -/** - * Get all Jetpack Social options. - * - * @returns {object} Object with Jetpack Social options. - */ -export function getJetpackSocialOptions() { - const { getEditedPostAttribute } = select( editorStore ); - const meta = getEditedPostAttribute( 'meta' ); - return get( meta, [ 'jetpack_social_options' ], {} ); -} - -/** - * Get whether the post has already been shared. - * - * @returns {object} Object with Jetpack Social options. - */ -export function getJetpackSocialPostAlreadyShared() { - const { getEditedPostAttribute } = select( editorStore ); - const meta = getEditedPostAttribute( 'meta' ); - return get( meta, [ 'jetpack_social_post_already_shared' ], {} ); -} - -/** - * Get a list of all attached media. - * - * @returns {Array<{id: string; url: string}>} An array of media IDs. - */ -export function getAttachedMedia() { - return get( getJetpackSocialOptions(), [ 'attached_media' ], [] ); -} - -/** - * Checks if the post is a social post. - * - * @returns {boolean} Whether the post is a social post. - */ -export function shouldUploadAttachedMedia() { - return getJetpackSocialOptions()?.should_upload_attached_media ?? false; -} - -/** - * Get the image generator settings for a post. - * - * @returns {object} An object of image generator settings. - */ -export function getImageGeneratorPostSettings() { - return getJetpackSocialOptions()?.image_generator_settings ?? {}; -} - -/** - * Checks if the Instagram connection is supported. - * - * @returns {boolean} Whether the Instagram connection is supported - */ -export function isInstagramConnectionSupported() { - return !! getJetpackData()?.social?.isInstagramConnectionSupported; -} - -/** - * Checks if the Instagram connection is supported. - * - * @returns {boolean} Whether the Instagram connection is supported - */ -export function isNextdoorConnectionSupported() { - return !! getJetpackData()?.social?.isNextdoorConnectionSupported; -} - -/** - * Checks if the Mastodon connection is supported. - * - * @returns {boolean} Whether the Mastodon connection is supported - */ -export function isMastodonConnectionSupported() { - return !! getJetpackData()?.social?.isMastodonConnectionSupported; -} diff --git a/projects/js-packages/publicize-components/src/utils/get-attached-media.js b/projects/js-packages/publicize-components/src/utils/get-attached-media.js new file mode 100644 index 0000000000000..a364871ea1579 --- /dev/null +++ b/projects/js-packages/publicize-components/src/utils/get-attached-media.js @@ -0,0 +1,11 @@ +import { getJetpackSocialOptions } from './get-jetpack-social-options'; +import { AttachedMedia } from './types'; + +/** + * Get a list of all attached media. + * + * @returns {Array} An array of media IDs. + */ +export function getAttachedMedia() { + return getJetpackSocialOptions().attached_media || []; +} diff --git a/projects/js-packages/publicize-components/src/utils/get-image-generator-post-settings.js b/projects/js-packages/publicize-components/src/utils/get-image-generator-post-settings.js new file mode 100644 index 0000000000000..a07fa22088501 --- /dev/null +++ b/projects/js-packages/publicize-components/src/utils/get-image-generator-post-settings.js @@ -0,0 +1,11 @@ +import { getJetpackSocialOptions } from './get-jetpack-social-options'; +import { SIGSettings } from './types'; + +/** + * Get the image generator settings for a post. + * + * @returns {SIGSettings} An object of image generator settings. + */ +export function getImageGeneratorPostSettings() { + return getJetpackSocialOptions()?.image_generator_settings ?? { enabled: false }; +} diff --git a/projects/js-packages/publicize-components/src/utils/get-jetpack-social-options.js b/projects/js-packages/publicize-components/src/utils/get-jetpack-social-options.js new file mode 100644 index 0000000000000..d9666862db8c7 --- /dev/null +++ b/projects/js-packages/publicize-components/src/utils/get-jetpack-social-options.js @@ -0,0 +1,15 @@ +import { select } from '@wordpress/data'; +import { store as editorStore } from '@wordpress/editor'; +import { JetpackSocialOptions } from './types'; + +/** + * Get all Jetpack Social options. + * + * @returns {JetpackSocialOptions} Object with Jetpack Social options. + */ +export function getJetpackSocialOptions() { + const { getEditedPostAttribute } = select( editorStore ); + const meta = getEditedPostAttribute( 'meta' ); + + return meta?.jetpack_social_options || {}; +} diff --git a/projects/js-packages/publicize-components/src/utils/get-jetpack-social-post-already-shared.js b/projects/js-packages/publicize-components/src/utils/get-jetpack-social-post-already-shared.js new file mode 100644 index 0000000000000..cd5cc74006f44 --- /dev/null +++ b/projects/js-packages/publicize-components/src/utils/get-jetpack-social-post-already-shared.js @@ -0,0 +1,15 @@ +import { select } from '@wordpress/data'; +import { store as editorStore } from '@wordpress/editor'; + +/** + * Get whether the post has already been shared. + * + * @returns {boolean} Object with Jetpack Social options. + */ +export function getJetpackSocialPostAlreadyShared() { + const { getEditedPostAttribute } = select( editorStore ); + + const alreadyShared = getEditedPostAttribute( 'meta' )?.jetpack_social_post_already_shared; + + return alreadyShared ?? false; +} diff --git a/projects/js-packages/publicize-components/src/utils/get-share-message-max-length.js b/projects/js-packages/publicize-components/src/utils/get-share-message-max-length.js new file mode 100644 index 0000000000000..b1817ee28f831 --- /dev/null +++ b/projects/js-packages/publicize-components/src/utils/get-share-message-max-length.js @@ -0,0 +1,14 @@ +// Links and media attached to tweets take up 24 characters each. +const ATTACHMENT_MESSAGE_PADDING = 24; + +// The maximum length is 280 characters, but there'll always be a URL attached (plus a space). +const MAXIMUM_MESSAGE_LENGTH = 280 - ATTACHMENT_MESSAGE_PADDING - 1; + +/** + * Get the maximum length that a share message can be. + * + * @returns {number} The maximum length of a share message. + */ +export function getShareMessageMaxLength() { + return MAXIMUM_MESSAGE_LENGTH; +} diff --git a/projects/js-packages/publicize-components/src/utils/get-share-message.js b/projects/js-packages/publicize-components/src/utils/get-share-message.js new file mode 100644 index 0000000000000..78c7adbab12d8 --- /dev/null +++ b/projects/js-packages/publicize-components/src/utils/get-share-message.js @@ -0,0 +1,20 @@ +import { select } from '@wordpress/data'; +import { store as editorStore } from '@wordpress/editor'; +import { getShareMessageMaxLength } from './get-share-message-max-length'; + +/** + * Gets the message that will be used hen sharing this post. + * + * @returns {string} The share message. + */ +export function getShareMessage() { + const { getEditedPostAttribute } = select( editorStore ); + const meta = getEditedPostAttribute( 'meta' ); + const message = `${ meta?.jetpack_publicize_message || '' }`; + + if ( message ) { + return message.substring( 0, getShareMessageMaxLength() ); + } + + return ''; +} diff --git a/projects/js-packages/publicize-components/src/utils/get-supported-additional-connections.js b/projects/js-packages/publicize-components/src/utils/get-supported-additional-connections.js new file mode 100644 index 0000000000000..7b4b3896eda45 --- /dev/null +++ b/projects/js-packages/publicize-components/src/utils/get-supported-additional-connections.js @@ -0,0 +1,10 @@ +import { getJetpackData } from '@automattic/jetpack-shared-extension-utils'; + +/** + * Get a list of additional connections that are supported by the current plan. + * + * @returns {Array} A list of connection names + */ +export function getSupportedAdditionalConnections() { + return getJetpackData()?.social?.supportedAdditionalConnections || []; +} diff --git a/projects/js-packages/publicize-components/src/utils/index.js b/projects/js-packages/publicize-components/src/utils/index.js new file mode 100644 index 0000000000000..2abd95aab448c --- /dev/null +++ b/projects/js-packages/publicize-components/src/utils/index.js @@ -0,0 +1,11 @@ +export * from './get-attached-media'; +export * from './get-image-generator-post-settings'; +export * from './get-jetpack-social-options'; +export * from './get-jetpack-social-post-already-shared'; +export * from './get-share-message'; +export * from './get-share-message-max-length'; +export * from './get-supported-additional-connections'; +export * from './is-publicize-enabled'; +export * from './should-upload-attached-media'; +export * from './toggle-publicize-feature'; +export * from './types'; diff --git a/projects/js-packages/publicize-components/src/utils/is-publicize-enabled.js b/projects/js-packages/publicize-components/src/utils/is-publicize-enabled.js new file mode 100644 index 0000000000000..ccaf6100bbeeb --- /dev/null +++ b/projects/js-packages/publicize-components/src/utils/is-publicize-enabled.js @@ -0,0 +1,16 @@ +import { select } from '@wordpress/data'; +import { store as editorStore } from '@wordpress/editor'; + +/** + * Return True if Publicize Feature is enabled. + * Otherwise, return False. + * + * @returns {boolean} Whether or not the publicize feature is enabled. + */ +export function isPublicizeEnabled() { + const { getEditedPostAttribute } = select( editorStore ); + + const enabled = getEditedPostAttribute( 'meta' )?.jetpack_publicize_feature_enabled; + + return enabled ?? true; +} diff --git a/projects/js-packages/publicize-components/src/utils/should-upload-attached-media.js b/projects/js-packages/publicize-components/src/utils/should-upload-attached-media.js new file mode 100644 index 0000000000000..2925311657ff0 --- /dev/null +++ b/projects/js-packages/publicize-components/src/utils/should-upload-attached-media.js @@ -0,0 +1,10 @@ +import { getJetpackSocialOptions } from './get-jetpack-social-options'; + +/** + * Checks if the post is a social post. + * + * @returns {boolean} Whether the post is a social post. + */ +export function shouldUploadAttachedMedia() { + return getJetpackSocialOptions().should_upload_attached_media ?? false; +} diff --git a/projects/js-packages/publicize-components/src/utils/test-utils.js b/projects/js-packages/publicize-components/src/utils/test-utils.js new file mode 100644 index 0000000000000..ef3547ae5eaa0 --- /dev/null +++ b/projects/js-packages/publicize-components/src/utils/test-utils.js @@ -0,0 +1,56 @@ +import { store as coreStore } from '@wordpress/core-data'; +import { dispatch } from '@wordpress/data'; +import { store as editorStore } from '@wordpress/editor'; + +const postId = 44; + +const postTypeConfig = { + kind: 'postType', + name: 'post', + baseURL: '/wp/v2/posts', + transientEdits: { blocks: true, selection: true }, + mergedEdits: { meta: true }, + rawAttributes: [ 'title', 'excerpt', 'content' ], +}; + +const postTypeEntity = { + slug: 'post', + rest_base: 'posts', + labels: {}, +}; + +const post = { + id: postId, + type: 'post', + title: 'bar', + content: 'bar', + excerpt: 'crackers', + status: 'draft', +}; + +/** + * Init the editor + */ +export function initEditor() { + // Register post type entity. + dispatch( coreStore ).addEntities( [ postTypeConfig ] ); + + // Store post type entity. + dispatch( coreStore ).receiveEntityRecords( 'root', 'postType', [ postTypeEntity ] ); + + // Store post. + dispatch( coreStore ).receiveEntityRecords( 'postType', 'post', post ); + + // Setup editor with post. + dispatch( editorStore ).setupEditor( post ); + // dispatch( editorStore ).setupEditorState( post ); +} + +/** + * Reset editor. + * + * @param {object} postAttributes - Attributes to reset. + */ +export async function resetEditor( postAttributes ) { + dispatch( editorStore ).editPost( postAttributes ); +} diff --git a/projects/js-packages/publicize-components/src/utils/test/get-attached-media.js b/projects/js-packages/publicize-components/src/utils/test/get-attached-media.js new file mode 100644 index 0000000000000..de00254b379c0 --- /dev/null +++ b/projects/js-packages/publicize-components/src/utils/test/get-attached-media.js @@ -0,0 +1,44 @@ +import { dispatch } from '@wordpress/data'; +import { store as editorStore } from '@wordpress/editor'; +import { getAttachedMedia } from '..'; +import { initEditor, resetEditor } from '../test-utils'; + +describe( 'getAttachedMedia', () => { + beforeEach( () => { + initEditor(); + } ); + + afterEach( () => { + resetEditor( { + meta: { + jetpack_social_options: undefined, + }, + } ); + } ); + + it( 'returns an empty array by default', () => { + expect( getAttachedMedia() ).toEqual( [] ); + } ); + + it( 'returns the values from post meta', () => { + dispatch( editorStore ).editPost( { + meta: { + jetpack_social_options: { + attached_media: [ { id: 1243 } ], + }, + }, + } ); + + expect( getAttachedMedia() ).toEqual( [ { id: 1243 } ] ); + + dispatch( editorStore ).editPost( { + meta: { + jetpack_social_options: { + attached_media: [], + }, + }, + } ); + + expect( getAttachedMedia() ).toEqual( [] ); + } ); +} ); diff --git a/projects/js-packages/publicize-components/src/utils/test/get-image-generator-post-settings.js b/projects/js-packages/publicize-components/src/utils/test/get-image-generator-post-settings.js new file mode 100644 index 0000000000000..d45470c7fe27d --- /dev/null +++ b/projects/js-packages/publicize-components/src/utils/test/get-image-generator-post-settings.js @@ -0,0 +1,50 @@ +import { dispatch } from '@wordpress/data'; +import { store as editorStore } from '@wordpress/editor'; +import { getImageGeneratorPostSettings } from '..'; +import { initEditor, resetEditor } from '../test-utils'; + +describe( 'getImageGeneratorPostSettings', () => { + beforeEach( () => { + initEditor(); + } ); + + afterEach( () => { + resetEditor( { + meta: { + jetpack_social_options: undefined, + }, + } ); + } ); + + it( 'returns the default object by default', () => { + expect( getImageGeneratorPostSettings() ).toEqual( { enabled: false } ); + } ); + + it( 'returns the values from post meta', () => { + dispatch( editorStore ).editPost( { + meta: { + jetpack_social_options: { + image_generator_settings: { + enabled: false, + template: 'test', + }, + }, + }, + } ); + + expect( getImageGeneratorPostSettings() ).toEqual( { + enabled: false, + template: 'test', + } ); + + dispatch( editorStore ).editPost( { + meta: { + jetpack_social_options: { + image_generator_settings: {}, + }, + }, + } ); + + expect( getImageGeneratorPostSettings() ).toEqual( {} ); + } ); +} ); diff --git a/projects/js-packages/publicize-components/src/utils/test/get-jetpack-social-options.js b/projects/js-packages/publicize-components/src/utils/test/get-jetpack-social-options.js new file mode 100644 index 0000000000000..f6b2ed03f3849 --- /dev/null +++ b/projects/js-packages/publicize-components/src/utils/test/get-jetpack-social-options.js @@ -0,0 +1,36 @@ +import { dispatch } from '@wordpress/data'; +import { store as editorStore } from '@wordpress/editor'; +import { getJetpackSocialOptions } from '..'; +import { initEditor, resetEditor } from '../test-utils'; + +describe( 'getJetpackSocialOptions', () => { + beforeEach( () => { + initEditor(); + } ); + + afterEach( () => { + resetEditor( { + meta: { + jetpack_social_options: undefined, + }, + } ); + } ); + + it( 'returns an empty object by default', () => { + expect( getJetpackSocialOptions() ).toEqual( {} ); + } ); + + it( 'returns the values from post meta', () => { + dispatch( editorStore ).editPost( { + meta: { + jetpack_social_options: { + some_option: 'some value', + }, + }, + } ); + + expect( getJetpackSocialOptions() ).toEqual( { + some_option: 'some value', + } ); + } ); +} ); diff --git a/projects/js-packages/publicize-components/src/utils/test/get-jetpack-social-post-already-shared.js b/projects/js-packages/publicize-components/src/utils/test/get-jetpack-social-post-already-shared.js new file mode 100644 index 0000000000000..9e6830f1f5f9f --- /dev/null +++ b/projects/js-packages/publicize-components/src/utils/test/get-jetpack-social-post-already-shared.js @@ -0,0 +1,40 @@ +import { dispatch } from '@wordpress/data'; +import { store as editorStore } from '@wordpress/editor'; +import { getJetpackSocialPostAlreadyShared } from '..'; +import { initEditor, resetEditor } from '../test-utils'; + +describe( 'getJetpackSocialPostAlreadyShared', () => { + beforeEach( () => { + initEditor(); + } ); + + afterEach( () => { + resetEditor( { + meta: { + jetpack_social_post_already_shared: undefined, + }, + } ); + } ); + + it( 'returns the default value', () => { + expect( getJetpackSocialPostAlreadyShared() ).toBe( false ); + } ); + + it( 'returns value from post meta', () => { + dispatch( editorStore ).editPost( { + meta: { + jetpack_social_post_already_shared: true, + }, + } ); + + expect( getJetpackSocialPostAlreadyShared() ).toBe( true ); + + dispatch( editorStore ).editPost( { + meta: { + jetpack_social_post_already_shared: false, + }, + } ); + + expect( getJetpackSocialPostAlreadyShared() ).toBe( false ); + } ); +} ); diff --git a/projects/js-packages/publicize-components/src/utils/test/get-share-message.js b/projects/js-packages/publicize-components/src/utils/test/get-share-message.js new file mode 100644 index 0000000000000..5adf050b9e464 --- /dev/null +++ b/projects/js-packages/publicize-components/src/utils/test/get-share-message.js @@ -0,0 +1,43 @@ +import { dispatch } from '@wordpress/data'; +import { store as editorStore } from '@wordpress/editor'; +import { getShareMessageMaxLength } from '..'; +import { getShareMessage } from '../get-share-message'; +import { initEditor, resetEditor } from '../test-utils'; + +describe( 'getShareMessage', () => { + beforeEach( () => { + initEditor(); + } ); + + afterEach( () => { + resetEditor( { + meta: { + jetpack_publicize_message: '', + }, + } ); + } ); + + it( 'returns an empty string by default', () => { + expect( getShareMessage() ).toBe( '' ); + } ); + + it( 'returns the message saved in post meta', () => { + dispatch( editorStore ).editPost( { + meta: { + jetpack_publicize_message: 'test message', + }, + } ); + + expect( getShareMessage() ).toBe( 'test message' ); + } ); + + it( 'truncates the message to the max length', () => { + dispatch( editorStore ).editPost( { + meta: { + jetpack_publicize_message: 'aaa'.repeat( 500 ), + }, + } ); + + expect( getShareMessage() ).toBe( 'a'.repeat( getShareMessageMaxLength() ) ); + } ); +} ); diff --git a/projects/js-packages/publicize-components/src/utils/test/is-publicize-enabled.js b/projects/js-packages/publicize-components/src/utils/test/is-publicize-enabled.js new file mode 100644 index 0000000000000..0d98bd8875080 --- /dev/null +++ b/projects/js-packages/publicize-components/src/utils/test/is-publicize-enabled.js @@ -0,0 +1,40 @@ +import { dispatch } from '@wordpress/data'; +import { store as editorStore } from '@wordpress/editor'; +import { isPublicizeEnabled } from '..'; +import { initEditor, resetEditor } from '../test-utils'; + +describe( 'isPublicizeEnabled', () => { + beforeEach( () => { + initEditor(); + } ); + + afterEach( () => { + resetEditor( { + meta: { + jetpack_publicize_feature_enabled: undefined, + }, + } ); + } ); + + it( 'returns the default value', () => { + expect( isPublicizeEnabled() ).toBe( true ); + } ); + + it( 'returns value from post meta', () => { + dispatch( editorStore ).editPost( { + meta: { + jetpack_publicize_feature_enabled: false, + }, + } ); + + expect( isPublicizeEnabled() ).toBe( false ); + + dispatch( editorStore ).editPost( { + meta: { + jetpack_publicize_feature_enabled: true, + }, + } ); + + expect( isPublicizeEnabled() ).toBe( true ); + } ); +} ); diff --git a/projects/js-packages/publicize-components/src/utils/test/should-upload-attached-media.js b/projects/js-packages/publicize-components/src/utils/test/should-upload-attached-media.js new file mode 100644 index 0000000000000..5f9b696dc0d31 --- /dev/null +++ b/projects/js-packages/publicize-components/src/utils/test/should-upload-attached-media.js @@ -0,0 +1,44 @@ +import { dispatch } from '@wordpress/data'; +import { store as editorStore } from '@wordpress/editor'; +import { shouldUploadAttachedMedia } from '..'; +import { initEditor, resetEditor } from '../test-utils'; + +describe( 'shouldUploadAttachedMedia', () => { + beforeEach( () => { + initEditor(); + } ); + + afterEach( () => { + resetEditor( { + meta: { + jetpack_social_options: undefined, + }, + } ); + } ); + + it( 'returns the default value', () => { + expect( shouldUploadAttachedMedia() ).toBe( false ); + } ); + + it( 'returns the values from post meta', () => { + dispatch( editorStore ).editPost( { + meta: { + jetpack_social_options: { + should_upload_attached_media: true, + }, + }, + } ); + + expect( shouldUploadAttachedMedia() ).toBe( true ); + + dispatch( editorStore ).editPost( { + meta: { + jetpack_social_options: { + should_upload_attached_media: false, + }, + }, + } ); + + expect( shouldUploadAttachedMedia() ).toBe( false ); + } ); +} ); diff --git a/projects/js-packages/publicize-components/src/utils/test/toggle-publicize-feature.js b/projects/js-packages/publicize-components/src/utils/test/toggle-publicize-feature.js new file mode 100644 index 0000000000000..41b841a86a1ce --- /dev/null +++ b/projects/js-packages/publicize-components/src/utils/test/toggle-publicize-feature.js @@ -0,0 +1,32 @@ +import { isPublicizeEnabled, togglePublicizeFeature } from '..'; +import { initEditor, resetEditor } from '../test-utils'; + +describe( 'togglePublicizeFeature', () => { + beforeEach( () => { + initEditor(); + } ); + + afterEach( () => { + resetEditor( { + meta: { + jetpack_publicize_message: '', + }, + } ); + } ); + + it( 'toggles the feature ON and OFF', () => { + const valueBeforeToggle = isPublicizeEnabled(); + + togglePublicizeFeature(); + + const valueAfterToggle = isPublicizeEnabled(); + + expect( valueBeforeToggle ).toBe( ! valueAfterToggle ); + + togglePublicizeFeature(); + + const valueAfterSecondToggle = isPublicizeEnabled(); + + expect( valueAfterToggle ).toBe( ! valueAfterSecondToggle ); + } ); +} ); diff --git a/projects/js-packages/publicize-components/src/utils/toggle-publicize-feature.js b/projects/js-packages/publicize-components/src/utils/toggle-publicize-feature.js new file mode 100644 index 0000000000000..d3fc51bbc81c7 --- /dev/null +++ b/projects/js-packages/publicize-components/src/utils/toggle-publicize-feature.js @@ -0,0 +1,16 @@ +import { dispatch } from '@wordpress/data'; +import { store as editorStore } from '@wordpress/editor'; +import { isPublicizeEnabled } from './is-publicize-enabled'; + +/** + * Toggle and store Post Share enable feature state. + * + * @returns {object} Updateting jetpack_publicize_feature_enabled post meta action. + */ +export function togglePublicizeFeature() { + const isPublicizeFeatureEnabled = isPublicizeEnabled(); + + return dispatch( editorStore ).editPost( { + meta: { jetpack_publicize_feature_enabled: ! isPublicizeFeatureEnabled }, + } ); +} diff --git a/projects/js-packages/publicize-components/src/utils/types.ts b/projects/js-packages/publicize-components/src/utils/types.ts new file mode 100644 index 0000000000000..d3db423afdff5 --- /dev/null +++ b/projects/js-packages/publicize-components/src/utils/types.ts @@ -0,0 +1,20 @@ +export type SIGSettings = { + enabled: boolean; + custom_text?: string; + image_type?: string; + image_id?: number; + template?: string; + token?: string; +}; + +export type AttachedMedia = { + id: number; + type: string; + url: string; +}; + +export type JetpackSocialOptions = { + attached_media?: Array< AttachedMedia >; + image_generator_settings?: SIGSettings; + should_upload_attached_media?: boolean; +}; diff --git a/projects/packages/publicize/changelog/update-remove-jetpack-publicize-store b/projects/packages/publicize/changelog/update-remove-jetpack-publicize-store new file mode 100644 index 0000000000000..97cf41efeb10a --- /dev/null +++ b/projects/packages/publicize/changelog/update-remove-jetpack-publicize-store @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Removed jetpack/publicize store diff --git a/projects/packages/publicize/src/class-publicize-base.php b/projects/packages/publicize/src/class-publicize-base.php index d346ff80ee608..0c6d339fd99f8 100644 --- a/projects/packages/publicize/src/class-publicize-base.php +++ b/projects/packages/publicize/src/class-publicize-base.php @@ -1803,6 +1803,40 @@ public function has_social_auto_conversion_feature( $type ) { return Current_Plan::supports( "social-$type-auto-convert" ); } + /** + * Check if a connection is enabled. + * + * @param string $connection The connection name like 'instagram', 'mastodon', 'nextdoor' etc. + * + * @return bool + */ + public function has_connection_feature( $connection ) { + return Current_Plan::supports( "social-$connection-connection" ); + } + + /** + * Get a list of additional connections that are supported by the current plan. + * + * @return array + */ + public function get_supported_additional_connections() { + $additional_connections = array(); + + if ( $this->has_connection_feature( 'instagram' ) ) { + $additional_connections[] = 'instagram-business'; + } + + if ( $this->has_connection_feature( 'mastodon' ) ) { + $additional_connections[] = 'mastodon'; + } + + if ( $this->has_connection_feature( 'nextdoor' ) ) { + $additional_connections[] = 'nextdoor'; + } + + return $additional_connections; + } + /** * Check if Instagram connection is enabled. * diff --git a/projects/plugins/jetpack/changelog/update-remove-jetpack-publicize-store b/projects/plugins/jetpack/changelog/update-remove-jetpack-publicize-store new file mode 100644 index 0000000000000..6eaa9e2079c6f --- /dev/null +++ b/projects/plugins/jetpack/changelog/update-remove-jetpack-publicize-store @@ -0,0 +1,4 @@ +Significance: patch +Type: other + +Removed jetpack/publicize store diff --git a/projects/plugins/jetpack/class.jetpack-gutenberg.php b/projects/plugins/jetpack/class.jetpack-gutenberg.php index 3e74abc90d4c9..7bc34ca0a28e7 100644 --- a/projects/plugins/jetpack/class.jetpack-gutenberg.php +++ b/projects/plugins/jetpack/class.jetpack-gutenberg.php @@ -737,9 +737,7 @@ public static function enqueue_block_editor_assets() { 'isSocialImageGeneratorAvailable' => $sig_settings->is_available(), 'isSocialImageGeneratorEnabled' => $sig_settings->is_enabled(), 'dismissedNotices' => $publicize->get_dismissed_notices(), - 'isInstagramConnectionSupported' => $publicize->has_instagram_connection_feature(), - 'isMastodonConnectionSupported' => $publicize->has_mastodon_connection_feature(), - 'isNextdoorConnectionSupported' => $publicize->has_nextdoor_connection_feature(), + 'supportedAdditionalConnections' => $publicize->get_supported_additional_connections(), 'autoConversionSettings' => array( 'available' => $auto_conversion_settings->is_available( 'image' ), 'image' => $auto_conversion_settings->is_enabled( 'image' ), diff --git a/projects/plugins/social/changelog/update-remove-jetpack-publicize-store b/projects/plugins/social/changelog/update-remove-jetpack-publicize-store new file mode 100644 index 0000000000000..1767a316a1499 --- /dev/null +++ b/projects/plugins/social/changelog/update-remove-jetpack-publicize-store @@ -0,0 +1,4 @@ +Significance: patch +Type: removed + +Removed jetpack/publicize store diff --git a/projects/plugins/social/src/class-jetpack-social.php b/projects/plugins/social/src/class-jetpack-social.php index a5ece3252cf84..73bef09b82f72 100644 --- a/projects/plugins/social/src/class-jetpack-social.php +++ b/projects/plugins/social/src/class-jetpack-social.php @@ -241,9 +241,7 @@ public function initial_state() { 'showNudge' => ! $publicize->has_paid_plan( true ), 'isEnhancedPublishingEnabled' => $publicize->has_enhanced_publishing_feature(), 'dismissedNotices' => $publicize->get_dismissed_notices(), - 'isInstagramConnectionSupported' => $publicize->has_instagram_connection_feature(), - 'isMastodonConnectionSupported' => $publicize->has_mastodon_connection_feature(), - 'isNextdoorConnectionSupported' => $publicize->has_nextdoor_connection_feature(), + 'supportedAdditionalConnections' => $publicize->get_supported_additional_connections(), ), 'connectionData' => array( 'connections' => $publicize->get_all_connections_for_user(), // TODO: Sanitize the array @@ -351,9 +349,8 @@ class_exists( 'Jetpack' ) || 'image' => $auto_conversion_settings->is_enabled( 'image' ), ), 'dismissedNotices' => $publicize->get_dismissed_notices(), - 'isInstagramConnectionSupported' => $publicize->has_instagram_connection_feature(), - 'isMastodonConnectionSupported' => $publicize->has_mastodon_connection_feature(), 'isNextdoorConnectionSupported' => $publicize->has_nextdoor_connection_feature(), + 'supportedAdditionalConnections' => $publicize->get_supported_additional_connections(), ), ) ); diff --git a/projects/plugins/social/src/js/components/instagram-notice/index.jsx b/projects/plugins/social/src/js/components/instagram-notice/index.jsx index 2db0a723b4d10..b5c59f93f2490 100644 --- a/projects/plugins/social/src/js/components/instagram-notice/index.jsx +++ b/projects/plugins/social/src/js/components/instagram-notice/index.jsx @@ -4,7 +4,12 @@ import { Notice, getRedirectUrl, } from '@automattic/jetpack-components'; -import { useDismissNotice, SOCIAL_STORE_ID } from '@automattic/jetpack-publicize-components'; +import { + useDismissNotice, + SOCIAL_STORE_ID, + getSupportedAdditionalConnections, + CONNECTION_SERVICE_INSTAGRAM_BUSINESS, +} from '@automattic/jetpack-publicize-components'; import { useSelect } from '@wordpress/data'; import { useCallback } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; @@ -22,21 +27,22 @@ const paidPlanNoticeText = __( const InstagramNotice = ( { onUpgrade = () => {} } = {} ) => { const { shouldShowNotice, dismissNotice, NOTICES } = useDismissNotice(); - const { connectionsAdminUrl, isInstagramConnectionSupported, isEnhancedPublishingEnabled } = - useSelect( select => { - const store = select( SOCIAL_STORE_ID ); - return { - connectionsAdminUrl: store.getConnectionsAdminUrl(), - isInstagramConnectionSupported: store.isInstagramConnectionSupported(), - isEnhancedPublishingEnabled: store.isEnhancedPublishingEnabled(), - }; - } ); + const { connectionsAdminUrl, isEnhancedPublishingEnabled } = useSelect( select => { + const store = select( SOCIAL_STORE_ID ); + return { + connectionsAdminUrl: store.getConnectionsAdminUrl(), + isEnhancedPublishingEnabled: store.isEnhancedPublishingEnabled(), + }; + } ); const handleDismiss = useCallback( () => { dismissNotice( NOTICES.instagram ); }, [ dismissNotice, NOTICES ] ); - if ( ! shouldShowNotice( NOTICES.instagram ) || ! isInstagramConnectionSupported ) { + if ( + ! shouldShowNotice( NOTICES.instagram ) || + ! getSupportedAdditionalConnections().includes( CONNECTION_SERVICE_INSTAGRAM_BUSINESS ) + ) { return null; } diff --git a/projects/plugins/social/src/js/components/publicize-panel/index.jsx b/projects/plugins/social/src/js/components/publicize-panel/index.jsx index 59d3003a2f213..8f140209d89c5 100644 --- a/projects/plugins/social/src/js/components/publicize-panel/index.jsx +++ b/projects/plugins/social/src/js/components/publicize-panel/index.jsx @@ -9,9 +9,11 @@ import { useSocialMediaConnections as useSelectSocialMediaConnections, usePostJustPublished, usePublicizeConfig, + isPublicizeEnabled as isPublicizeFeatureEnabled, + togglePublicizeFeature, } from '@automattic/jetpack-publicize-components'; import { PanelBody, PanelRow, ToggleControl } from '@wordpress/components'; -import { useSelect, useDispatch } from '@wordpress/data'; +import { useSelect } from '@wordpress/data'; import { store as editorStore } from '@wordpress/editor'; import { Fragment } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; @@ -20,11 +22,7 @@ import Description from './description'; const PublicizePanel = ( { prePublish } ) => { const { refresh, hasConnections, hasEnabledConnections } = useSelectSocialMediaConnections(); const isPostPublished = useSelect( select => select( editorStore ).isCurrentPostPublished(), [] ); - const isPublicizeEnabled = useSelect( - select => select( 'jetpack/publicize' ).getFeatureEnableState(), - [] - ); - const { togglePublicizeFeature } = useDispatch( 'jetpack/publicize' ); + const isPublicizeEnabled = isPublicizeFeatureEnabled(); const { hasPaidPlan,