diff --git a/projects/plugins/boost/app/assets/src/js/features/cornerstone-pages/meta/meta.tsx b/projects/plugins/boost/app/assets/src/js/features/cornerstone-pages/meta/meta.tsx index 271bb7488d36d..59c287fc2ef8f 100644 --- a/projects/plugins/boost/app/assets/src/js/features/cornerstone-pages/meta/meta.tsx +++ b/projects/plugins/boost/app/assets/src/js/features/cornerstone-pages/meta/meta.tsx @@ -15,7 +15,7 @@ import { usePremiumFeatures } from '$lib/stores/premium-features'; import { useRegenerateCriticalCssAction } from '$features/critical-css/lib/stores/critical-css-state'; import { isSameSiteUrl } from '$lib/utils/is-same-site-url'; import UpgradeCTA from '$features/upgrade-cta/upgrade-cta'; - +import { useNotices } from '$features/notice/context'; const Meta = () => { const cornerstonePagesSupportLink = getRedirectUrl( 'jetpack-boost-cornerstone-pages' ); const [ cornerstonePages, setCornerstonePages ] = useCornerstonePages(); @@ -24,11 +24,17 @@ const Meta = () => { const premiumFeatures = usePremiumFeatures(); const isPremium = premiumFeatures.includes( 'cornerstone-10-pages' ); const regenerateAction = useRegenerateCriticalCssAction(); + const { setNotice } = useNotices(); const updateCornerstonePages = ( newValue: string ) => { const newItems = newValue.split( '\n' ).map( line => line.trim() ); setCornerstonePages( newItems, () => { + setNotice( { + id: 'cornerstone-pages-save', + type: 'success', + message: __( 'Cornerstone pages saved', 'jetpack-boost' ), + } ); refetchRegenerationReason(); if ( isPremium ) { regenerateAction.mutate(); @@ -151,7 +157,6 @@ const List: React.FC< ListProps > = ( { const premiumFeatures = usePremiumFeatures(); const isPremium = premiumFeatures.includes( 'cornerstone-10-pages' ); const cornerstonePagesProperties = useCornerstonePagesProperties(); - const validateInputValue = ( value: string ) => { setInputValue( value ); try { diff --git a/projects/plugins/boost/app/assets/src/js/features/image-cdn/image-cdn-liar/image-cdn-liar.tsx b/projects/plugins/boost/app/assets/src/js/features/image-cdn/image-cdn-liar/image-cdn-liar.tsx index d6862e9b6e9e4..03019a2a81469 100644 --- a/projects/plugins/boost/app/assets/src/js/features/image-cdn/image-cdn-liar/image-cdn-liar.tsx +++ b/projects/plugins/boost/app/assets/src/js/features/image-cdn/image-cdn-liar/image-cdn-liar.tsx @@ -6,6 +6,7 @@ import styles from './image-cdn-liar.module.scss'; import ModuleSubsection from '$features/ui/module-subsection/module-subsection'; import { recordBoostEvent } from '$lib/utils/analytics'; import Pill from '$features/ui/pill/pill'; +import { useMutationNotice } from '$features/ui/mutation-notice/mutation-notice'; type ImageCdnLiarProps = { isPremium: boolean; @@ -22,6 +23,12 @@ export default function ImageCdnLiar( { isPremium }: ImageCdnLiarProps ) { z.boolean().catch( false ) ); + const enabledMessage = __( 'Auto-resize enabled.', 'jetpack-boost' ); + const disabledMessage = __( 'Auto-resize disabled.', 'jetpack-boost' ); + useMutationNotice( 'image-cdn-liar', setImageCdnLiar, { + successMessage: imageCdnLiar.data ? enabledMessage : disabledMessage, + } ); + const handleToggle = ( value: boolean ) => { setImageCdnLiar.mutate( value ); diff --git a/projects/plugins/boost/app/assets/src/js/features/image-cdn/quality-settings/quality-settings.tsx b/projects/plugins/boost/app/assets/src/js/features/image-cdn/quality-settings/quality-settings.tsx index 8e44f312efcc1..60e055ebd8ca9 100644 --- a/projects/plugins/boost/app/assets/src/js/features/image-cdn/quality-settings/quality-settings.tsx +++ b/projects/plugins/boost/app/assets/src/js/features/image-cdn/quality-settings/quality-settings.tsx @@ -6,6 +6,7 @@ import QualityControl from '../quality-control/quality-control'; import { imageCdnSettingsSchema, useImageCdnQuality } from '../lib/stores'; import { z } from 'zod'; import ModuleSubsection from '$features/ui/module-subsection/module-subsection'; +import { useMutationNotice } from '$features/ui/mutation-notice/mutation-notice'; type QualitySettingsProps = { isPremium: boolean; @@ -20,6 +21,8 @@ const QualitySettings = ( { isPremium }: QualitySettingsProps ) => { const imageCdnQuality = query?.data; const setImageCdnQuality = mutation.mutate; + useMutationNotice( 'image-cdn-quality', mutation ); + const setQuality = ( format: 'jpg' | 'png' | 'webp', newValue: number ) => { if ( ! setImageCdnQuality || ! imageCdnQuality ) { return; diff --git a/projects/plugins/boost/app/assets/src/js/features/minify-meta/minify-meta.tsx b/projects/plugins/boost/app/assets/src/js/features/minify-meta/minify-meta.tsx index e882d8240a743..af28438373996 100644 --- a/projects/plugins/boost/app/assets/src/js/features/minify-meta/minify-meta.tsx +++ b/projects/plugins/boost/app/assets/src/js/features/minify-meta/minify-meta.tsx @@ -1,15 +1,26 @@ -import { useEffect, useState } from 'react'; +import { useState } from 'react'; import { Button } from '@automattic/jetpack-components'; import { __, sprintf } from '@wordpress/i18n'; import { type Props, useMetaQuery } from '$lib/stores/minify'; import { recordBoostEvent } from '$lib/utils/analytics'; import styles from './minify-meta.module.scss'; import CollapsibleMeta from '$features/ui/collapsible-meta/collapsible-meta'; +import { useNotices } from '$features/notice/context'; import { useMinifyDefaults } from './lib/stores'; const MetaComponent = ( { buttonText, placeholder, datasyncKey }: Props ) => { - const [ values, updateValues ] = useMetaQuery( datasyncKey ); + const noticeId = `minify-meta-${ datasyncKey }`; + + const [ values, updateValues ] = useMetaQuery( datasyncKey, newState => { + setInputValue( newState.join( ', ' ) ); + setNotice( { + id: noticeId, + type: 'success', + message: __( 'Changes saved', 'jetpack-boost' ), + } ); + } ); const [ inputValue, setInputValue ] = useState( () => values.join( ', ' ) ); + const { setNotice } = useNotices(); const minifyDefaults = useMinifyDefaults( datasyncKey ); const concatenateType = datasyncKey === 'minify_js_excludes' ? 'js' : 'css'; @@ -20,10 +31,6 @@ const MetaComponent = ( { buttonText, placeholder, datasyncKey }: Props ) => { defaultValue = minifyDefaults.join( ', ' ); } - useEffect( () => { - setInputValue( values.join( ', ' ) ); - }, [ values ] ); - const onToggleHandler = ( isExpanded: boolean ) => { if ( ! isExpanded ) { setInputValue( values.join( ', ' ) ); @@ -38,6 +45,13 @@ const MetaComponent = ( { buttonText, placeholder, datasyncKey }: Props ) => { */ recordBoostEvent( 'concatenate_' + concatenateType + '_exceptions_save_clicked', {} ); + // Show saving notice + setNotice( { + id: noticeId, + type: 'pending', + message: __( 'Saving…', 'jetpack-boost' ), + } ); + updateValues( inputValue ); } diff --git a/projects/plugins/boost/app/assets/src/js/features/module/module.tsx b/projects/plugins/boost/app/assets/src/js/features/module/module.tsx index 947bc44d061e4..3e6ecdadb2c81 100644 --- a/projects/plugins/boost/app/assets/src/js/features/module/module.tsx +++ b/projects/plugins/boost/app/assets/src/js/features/module/module.tsx @@ -5,6 +5,7 @@ import styles from './module.module.scss'; import ErrorBoundary from '$features/error-boundary/error-boundary'; import { __ } from '@wordpress/i18n'; import { isWoaHosting } from '$lib/utils/hosting'; +import { useNotices } from '$features/notice/context'; type ModuleProps = { title: React.ReactNode; @@ -29,7 +30,16 @@ const Module = ( { onDisable, onMountEnable, }: ModuleProps ) => { + const { setNotice } = useNotices(); const [ status, setStatus ] = useSingleModuleState( slug, active => { + const activatedMessage = __( 'Module activated', 'jetpack-boost' ); + const deactivatedMessage = __( 'Module deactivated', 'jetpack-boost' ); + + setNotice( { + id: 'update-module-state', + type: 'success', + message: active ? activatedMessage : deactivatedMessage, + } ); if ( active ) { onEnable?.(); } else { @@ -43,10 +53,20 @@ const Module = ( { const isFakeActive = ! isModuleAvailable && isWoaHosting() && slug === 'page_cache'; const handleToggle = () => { + const newState = ! isModuleActive; + const deactivateMessage = __( 'Deactivating module', 'jetpack-boost' ); + const activateMessage = __( 'Activating module', 'jetpack-boost' ); + + setNotice( { + id: 'update-module-state', + type: 'pending', + message: newState ? activateMessage : deactivateMessage, + } ); + if ( onBeforeToggle ) { - onBeforeToggle( ! isModuleActive ); + onBeforeToggle( newState ); } - setStatus( ! isModuleActive ); + setStatus( newState ); }; useEffect( () => { diff --git a/projects/plugins/boost/app/assets/src/js/features/notice/manager.tsx b/projects/plugins/boost/app/assets/src/js/features/notice/manager.tsx index 1dcbb3b16d95c..e869dcf6456fb 100644 --- a/projects/plugins/boost/app/assets/src/js/features/notice/manager.tsx +++ b/projects/plugins/boost/app/assets/src/js/features/notice/manager.tsx @@ -14,7 +14,7 @@ const Notice = ( { notice, onDismiss }: NoticeProps ) => { if ( notice.type !== 'pending' ) { onDismiss(); } - }, 5000 ); + }, 2000 ); return () => clearTimeout( timer ); }, [ onDismiss, notice ] ); diff --git a/projects/plugins/boost/app/assets/src/js/lib/stores/minify.ts b/projects/plugins/boost/app/assets/src/js/lib/stores/minify.ts index f7299600e7d71..88aae1c74ca68 100644 --- a/projects/plugins/boost/app/assets/src/js/lib/stores/minify.ts +++ b/projects/plugins/boost/app/assets/src/js/lib/stores/minify.ts @@ -11,11 +11,19 @@ export interface Props { placeholder: string; } -export const useMetaQuery = ( key: MinifyMetaKeys ) => { +export const useMetaQuery = ( key: MinifyMetaKeys, onSuccess?: ( newState: string[] ) => void ) => { const [ { data }, { mutate } ] = useDataSync( 'jetpack_boost_ds', key, z.array( z.string() ) ); function updateValues( text: string ) { - mutate( text.split( ',' ).map( item => item.trim() ) ); + mutate( + text.split( ',' ).map( item => item.trim() ), + { + onSuccess: newState => { + // Run the passed on callbacks after the mutation has been applied + onSuccess?.( newState ); + }, + } + ); } return [ data || [], updateValues ] as const; diff --git a/projects/plugins/boost/app/assets/src/js/pages/index/index.tsx b/projects/plugins/boost/app/assets/src/js/pages/index/index.tsx index 7094ffd289914..0b26f93b6eb84 100644 --- a/projects/plugins/boost/app/assets/src/js/pages/index/index.tsx +++ b/projects/plugins/boost/app/assets/src/js/pages/index/index.tsx @@ -27,6 +27,7 @@ const Index = () => { const [ imageCdn ] = useSingleModuleState( 'image_cdn' ); const regenerateCssAction = useRegenerateCriticalCssAction(); + const requestRegenerateCriticalCss = () => { regenerateCssAction.mutate(); }; diff --git a/projects/plugins/boost/changelog/update-boost-add-notices-to-settings-page b/projects/plugins/boost/changelog/update-boost-add-notices-to-settings-page new file mode 100644 index 0000000000000..73d537e320740 --- /dev/null +++ b/projects/plugins/boost/changelog/update-boost-add-notices-to-settings-page @@ -0,0 +1,4 @@ +Significance: minor +Type: added + +UI: Add notifications when interacting with dashboard settings.