-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Newsletter: use with-site-settings.js
- Loading branch information
Showing
4 changed files
with
314 additions
and
181 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { useQuery } from '@tanstack/react-query'; | ||
import wp from 'calypso/lib/wp'; | ||
|
||
const useSiteSettingsQuery = ( siteId ) => | ||
useQuery( { | ||
queryKey: [ 'site-settings', siteId ], | ||
queryFn: () => wp.req.get( `/sites/${ siteId }/settings`, { apiVersion: '1.4' } ), | ||
refetchOnWindowFocus: false, | ||
enabled: !! siteId, | ||
meta: { | ||
persist: false, | ||
}, | ||
} ); | ||
|
||
export default useSiteSettingsQuery; |
26 changes: 26 additions & 0 deletions
26
client/data/site-settings/use-update-site-settings-mutation.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { useMutation, useQueryClient } from '@tanstack/react-query'; | ||
import { useCallback } from 'react'; | ||
import wp from 'calypso/lib/wp'; | ||
|
||
function useUpdateSiteSettingsMutation( siteId, queryOptions = {} ) { | ||
const queryClient = useQueryClient(); | ||
const mutation = useMutation( { | ||
mutationFn: ( { settings } ) => | ||
wp.req.post( '/sites/' + siteId + '/settings', { apiVersion: '1.4' }, settings ), | ||
...queryOptions, | ||
onSuccess( ...args ) { | ||
queryClient.invalidateQueries( { | ||
queryKey: [ 'site-settings', siteId ], | ||
} ); | ||
queryOptions.onSuccess?.( ...args ); | ||
}, | ||
} ); | ||
|
||
const { mutate } = mutation; | ||
|
||
const updateSiteSettings = useCallback( ( settings ) => mutate( { settings } ), [ mutate ] ); | ||
|
||
return { updateSiteSettings, ...mutation }; | ||
} | ||
|
||
export default useUpdateSiteSettingsMutation; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
import { useQueryClient } from '@tanstack/react-query'; | ||
import { createHigherOrderComponent } from '@wordpress/compose'; | ||
import { useCallback, useState } from '@wordpress/element'; | ||
import { useTranslate } from 'i18n-calypso'; | ||
import PropTypes from 'prop-types'; | ||
import { useDispatch, useSelector } from 'react-redux'; | ||
import useSiteSettingsQuery from 'calypso/data/site-settings/use-site-settings-query'; | ||
import useUpdateSiteSettingsMutation from 'calypso/data/site-settings/use-update-site-settings-mutation'; | ||
import { recordGoogleEvent, recordTracksEvent } from 'calypso/state/analytics/actions'; | ||
import { errorNotice, successNotice } from 'calypso/state/notices/actions'; | ||
import getCurrentRouteParameterized from 'calypso/state/selectors/get-current-route-parameterized'; | ||
|
||
const noticeOptions = { | ||
duration: 10000, | ||
id: 'site-settings-save', | ||
}; | ||
|
||
const withSiteSettings = createHigherOrderComponent( ( Wrapped ) => { | ||
const WithSiteSettings = ( props ) => { | ||
const { siteId } = props; | ||
const [ unsavedSettings, setUnsavedSettings ] = useState( {} ); | ||
const dispatch = useDispatch(); | ||
const translate = useTranslate(); | ||
const queryClient = useQueryClient(); | ||
const path = useSelector( ( state ) => getCurrentRouteParameterized( state, siteId ) ); | ||
|
||
const trackEvent = useCallback( | ||
( name ) => { | ||
dispatch( recordGoogleEvent( 'Site Settings', name ) ); | ||
}, | ||
[ dispatch ] | ||
); | ||
|
||
const trackTracksEvent = useCallback( | ||
( name, eventProps ) => { | ||
dispatch( recordTracksEvent( name, eventProps ) ); | ||
}, | ||
[ dispatch ] | ||
); | ||
|
||
const { data, isLoading: isFetchingSettings } = useSiteSettingsQuery( siteId ); | ||
|
||
const updateSettings = useCallback( | ||
( fields ) => { | ||
return setUnsavedSettings( { ...unsavedSettings, ...fields } ); | ||
}, | ||
[ unsavedSettings, setUnsavedSettings ] | ||
); | ||
|
||
const { | ||
isPending: isSavingSettings, | ||
updateSiteSettings: saveSettings, | ||
context: mutateContext, | ||
} = useUpdateSiteSettingsMutation( siteId, { | ||
onMutate: async ( settings ) => { | ||
const queryKey = [ 'site-settings', siteId ]; | ||
|
||
// Cancel any current refetches, so they don't overwrite our optimistic update | ||
await queryClient.cancelQueries( { | ||
queryKey, | ||
} ); | ||
|
||
// Snapshot the previous value | ||
const previousSettings = queryClient.getQueryData( queryKey ); | ||
|
||
// Optimistically update to the new value | ||
queryClient.setQueryData( queryKey, ( { settings: oldSettings } ) => { | ||
return { ...oldSettings, ...settings }; | ||
} ); | ||
|
||
// Store previous settings in case of failure | ||
return { previousSettings }; | ||
}, | ||
onSuccess() { | ||
dispatch( successNotice( translate( 'Settings saved successfully!' ), noticeOptions ) ); | ||
setUnsavedSettings( {} ); // clear dirty fields after successful save. | ||
if ( path === '/settings/newsletter/:site' ) { | ||
trackTracksEvent( 'calypso_settings_newsletter_saved', unsavedSettings ); | ||
} | ||
}, | ||
onError( err, newSettings, context ) { | ||
// Revert to previous settings on failure | ||
queryClient.setQueryData( [ 'site-settings', siteId ], context.previousSettings ); | ||
|
||
dispatch( | ||
errorNotice( | ||
translate( 'There was a problem saving your changes. Please, try again.' ), | ||
noticeOptions | ||
) | ||
); | ||
}, | ||
onSettled: () => { | ||
// Refetch settings regardless | ||
queryClient.invalidateQueries( { | ||
queryKey: [ 'site-settings', siteId ], | ||
} ); | ||
}, | ||
} ); | ||
|
||
const handleSubmitForm = useCallback( () => { | ||
trackEvent( 'Clicked Save Settings Button' ); | ||
saveSettings( unsavedSettings ); | ||
if ( ! unsavedSettings ) { | ||
return; | ||
} | ||
trackEvent( 'Clicked Save Settings Button' ); | ||
}, [ saveSettings, unsavedSettings, trackEvent ] ); | ||
|
||
const handleToggle = useCallback( | ||
( name ) => () => { | ||
if ( unsavedSettings[ name ] === undefined ) { | ||
unsavedSettings[ name ] = data?.settings[ name ]; | ||
} | ||
updateSettings( { [ name ]: ! unsavedSettings[ name ] } ); | ||
trackEvent( `Toggled ${ name }` ); | ||
}, | ||
[ trackEvent, unsavedSettings, updateSettings, data?.settings ] | ||
); | ||
|
||
const settings = Object.assign( | ||
{}, | ||
mutateContext?.previousSettings?.settings, | ||
data?.settings, | ||
unsavedSettings | ||
); | ||
return ( | ||
<Wrapped | ||
{ ...props } | ||
settings={ settings } | ||
isLoadingSettings={ isFetchingSettings } | ||
isSavingSettings={ isSavingSettings } | ||
updateSettings={ updateSettings } | ||
unsavedSettings={ unsavedSettings } | ||
handleToggle={ handleToggle } | ||
handleSubmitForm={ handleSubmitForm } | ||
/> | ||
); | ||
}; | ||
|
||
WithSiteSettings.propTypes = { | ||
siteId: PropTypes.number.isRequired, | ||
}; | ||
|
||
return WithSiteSettings; | ||
}, 'WithSiteSettings' ); | ||
|
||
export default withSiteSettings; |
Oops, something went wrong.