Files
piratepoet/packages/js/email-editor/src/hooks/use-content-validation.ts
2025-02-07 15:30:20 +01:00

83 lines
2.2 KiB
TypeScript

/**
* External dependencies
*/
import { useCallback } from '@wordpress/element';
import { useSelect, subscribe } from '@wordpress/data';
import { store as coreDataStore } from '@wordpress/core-data';
import { applyFilters } from '@wordpress/hooks';
/**
* Internal dependencies
*/
import {
EmailContentValidationRule,
storeName as emailEditorStore,
} from '../store';
import { useShallowEqual } from './use-shallow-equal';
import { useValidationNotices } from './use-validation-notices';
// Shared reference to an empty array for cases where it is important to avoid
// returning a new array reference on every invocation
const EMPTY_ARRAY = [];
export type ContentValidationData = {
isInvalid: boolean;
validateContent: () => boolean;
};
export const useContentValidation = (): ContentValidationData => {
const { addValidationNotice, hasValidationNotice, removeValidationNotice } =
useValidationNotices();
const { editedContent, editedTemplateContent } = useSelect(
( mapSelect ) => ( {
editedContent:
mapSelect( emailEditorStore ).getEditedEmailContent(),
editedTemplateContent:
mapSelect( emailEditorStore ).getCurrentTemplateContent(),
} )
);
const rules: EmailContentValidationRule[] = applyFilters(
'mailpoet_email_editor_content_validation_rules',
EMPTY_ARRAY
) as EmailContentValidationRule[];
const content = useShallowEqual( editedContent );
const templateContent = useShallowEqual( editedTemplateContent );
const validateContent = useCallback( (): boolean => {
let isValid = true;
rules.forEach( ( { id, test, message, actions } ) => {
// Check both content and template content for the rule.
if ( test( content + templateContent ) ) {
addValidationNotice( id, message, actions );
isValid = false;
} else if ( hasValidationNotice( id ) ) {
removeValidationNotice( id );
}
} );
return isValid;
}, [
content,
templateContent,
addValidationNotice,
removeValidationNotice,
hasValidationNotice,
rules,
] );
// Subscribe to updates so notices can be dismissed once resolved.
subscribe( () => {
if ( ! hasValidationNotice() ) {
return;
}
validateContent();
}, coreDataStore );
return {
isInvalid: hasValidationNotice(),
validateContent,
};
};