HEX
Server: nginx
System: Linux pool195-106-36.bur.atomicsites.net 6.12.57+deb12-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.12.57-1~bpo12+1 (2025-11-17) x86_64
User: (0)
PHP: 8.3.32
Disabled: pcntl_fork
Upload Files
File: /wordpress/plugins/jetpack/16.0/_inc/content-guidelines-ai/store.js
import apiFetch from '@wordpress/api-fetch';
import { createReduxStore, register } from '@wordpress/data';

// Per-user dismissed flag, persisted server-side so it follows the user across
// devices/browsers. The initial value is preloaded into the page by PHP (see
// _inc/content-guidelines-ai.php); dismissal is written via this REST route.
const DISMISS_PATH = '/wpcom/v2/jetpack-ai/guidelines-banner-dismissed';

const DEFAULT_STATE = {
	loading: false,
	loadingSections: {},
	suggestions: {},
	bannerDismissed: !! window.jetpackContentGuidelinesAi?.bannerDismissed,
};

const actions = {
	startLoading() {
		return { type: 'START_LOADING' };
	},
	stopLoading() {
		return { type: 'STOP_LOADING' };
	},
	setSuggestion( slug, text ) {
		return { type: 'SET_SUGGESTION', slug, text };
	},
	clearSuggestion( slug ) {
		return { type: 'CLEAR_SUGGESTION', slug };
	},
	startSectionLoading( slug ) {
		return { type: 'START_SECTION_LOADING', slug };
	},
	stopSectionLoading( slug ) {
		return { type: 'STOP_SECTION_LOADING', slug };
	},
	dismissBanner() {
		return ( { select, dispatch } ) => {
			// One-way flag — skip the write if already dismissed.
			if ( select.isBannerDismissed() ) {
				return;
			}
			// Optimistic: update state now, persist per-user in the background.
			// A failed write is ignored — re-syncs from the preloaded value on
			// the next page load.
			dispatch( { type: 'DISMISS_BANNER' } );
			apiFetch( {
				method: 'PUT',
				path: DISMISS_PATH,
			} ).catch( () => {} );
		};
	},
};

function reducer( state = DEFAULT_STATE, action ) {
	switch ( action.type ) {
		case 'START_LOADING':
			return { ...state, loading: true };
		case 'STOP_LOADING':
			return { ...state, loading: false };
		case 'SET_SUGGESTION':
			return {
				...state,
				suggestions: { ...state.suggestions, [ action.slug ]: action.text },
			};
		case 'CLEAR_SUGGESTION': {
			const suggestions = { ...state.suggestions };
			delete suggestions[ action.slug ];
			return { ...state, suggestions };
		}
		case 'DISMISS_BANNER':
			return { ...state, bannerDismissed: true };
		case 'START_SECTION_LOADING':
			return {
				...state,
				loadingSections: { ...state.loadingSections, [ action.slug ]: true },
			};
		case 'STOP_SECTION_LOADING': {
			const loadingSections = { ...state.loadingSections };
			delete loadingSections[ action.slug ];
			return { ...state, loadingSections };
		}
		default:
			return state;
	}
}

const selectors = {
	isLoading( state ) {
		return state.loading;
	},
	getSuggestion( state, slug ) {
		return state.suggestions[ slug ] || '';
	},
	hasSuggestion( state, slug ) {
		return !! state.suggestions[ slug ];
	},
	isSectionLoading( state, slug ) {
		return state.loading || !! state.loadingSections[ slug ];
	},
	isBannerDismissed( state ) {
		return state.bannerDismissed;
	},
};

export const AI_STORE_NAME = 'jetpack/content-guidelines-ai';

const aiStore = createReduxStore( AI_STORE_NAME, {
	reducer,
	actions,
	selectors,
} );

register( aiStore );