Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | 81x 4x 4x 4x 4x 4x 4x 4x 7x 7x 7x 7x 7x 9x 9x 7x 7x 7x 4x 4x 4x 4x 3x 4x 4x 4x | import { store as coreStore, useEntityRecord } from '@wordpress/core-data';
import { useDispatch, useRegistry } from '@wordpress/data';
import { useCallback, useMemo, useRef } from 'react';
export type StatsSettings = {
admin_bar: boolean;
roles: string[];
count_roles: string[];
wpcom_reader_views_enabled: boolean;
};
type StatsOptions = Omit< StatsSettings, 'wpcom_reader_views_enabled' >;
type SiteSettings = {
stats_options?: StatsOptions;
wpcom_reader_views_enabled?: boolean;
};
const toSettings = ( site: SiteSettings | null | undefined ): StatsSettings | undefined =>
site?.stats_options && {
...site.stats_options,
wpcom_reader_views_enabled: Boolean( site.wpcom_reader_views_enabled ),
};
/**
* The Stats settings, read from core's site settings entity and saved as each change is made.
*
* @return The settings, and the action that saves a change.
*/
export function useStatsSettings() {
// The site settings entity has no ID.
const site = useEntityRecord< SiteSettings >( 'root', 'site', undefined as unknown as string );
const { editedRecord, edit } = site;
const { saveEditedEntityRecord } = useDispatch( coreStore );
const registry = useRegistry();
// The change that last edited each setting; a failed save puts back only the settings it still owns.
const owners = useRef( new Map< keyof StatsSettings, symbol >() );
/**
* Save a change, or put back the stored values of what it changed when the site refuses it.
*
* @param values - The changed settings.
* @return Resolves once saved; rejects with the site's error.
*/
const saveChange = useCallback(
async ( values: Partial< StatsSettings > ) => {
const change = Symbol();
( Object.keys( values ) as ( keyof StatsSettings )[] ).forEach( key =>
owners.current.set( key, change )
);
const { wpcom_reader_views_enabled: readerViews, ...options } = values;
// Read at call time: another change may have been edited or saved since the last render.
const read = () => {
const { getEntityRecord, getEditedEntityRecord } = registry.select( coreStore );
return {
stored: getEntityRecord( 'root', 'site' ) as SiteSettings | undefined,
edited: getEditedEntityRecord( 'root', 'site' ) as SiteSettings,
};
};
edit( {
...( Object.keys( options ).length > 0 && {
stats_options: { ...read().edited.stats_options, ...options },
} ),
...( readerViews !== undefined && { wpcom_reader_views_enabled: readerViews } ),
} );
try {
await saveEditedEntityRecord( 'root', 'site', undefined, { throwOnError: true } );
} catch ( error ) {
const isOwned = ( key: keyof StatsSettings ) => owners.current.get( key ) === change;
const optionKeys = ( Object.keys( options ) as ( keyof StatsOptions )[] ).filter( isOwned );
const { stored, edited } = read();
// Editing back to the stored values is how core-data drops an edit.
edit( {
...( optionKeys.length > 0 && {
stats_options: {
...edited.stats_options,
...Object.fromEntries(
optionKeys.map( key => [ key, stored?.stats_options?.[ key ] ] )
),
},
} ),
...( readerViews !== undefined &&
isOwned( 'wpcom_reader_views_enabled' ) && {
wpcom_reader_views_enabled: stored?.wpcom_reader_views_enabled,
} ),
} );
throw error;
}
},
[ edit, registry, saveEditedEntityRecord ]
);
const settings = useMemo( () => toSettings( editedRecord ), [ editedRecord ] );
return {
settings,
// The route answers `null` for a stored value its schema refuses.
isError: site.status === 'ERROR' || ( site.hasResolved && ! settings ),
saveChange,
};
}
|