Skip to content

Commit

Permalink
Check for unsaved changes before leaving product editor (woocommerce#…
Browse files Browse the repository at this point in the history
…38430)

* Check for unsaved changes before leaving product editor

* Add changelog entry

* Add hasEdit convenience method to useProductEdits hook
  • Loading branch information
joshuatf authored May 31, 2023
1 parent f0e6802 commit a5e3637
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 2 deletions.
4 changes: 4 additions & 0 deletions packages/js/product-editor/changelog/add-38253
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: add

Check for unsaved changes before leaving product editor
6 changes: 4 additions & 2 deletions packages/js/product-editor/src/blocks/schedule-sale/edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ import { getSettings } from '@wordpress/date';
* Internal dependencies
*/
import { ScheduleSalePricingBlockAttributes } from './types';
import { useProductEdits } from '../../hooks/use-product-edits';
import { useValidation } from '../../contexts/validation-context';

export function Edit( {
clientId,
}: BlockEditProps< ScheduleSalePricingBlockAttributes > ) {
const blockProps = useBlockProps();
const { hasEdit } = useProductEdits();

const dateTimeFormat = getSettings().formats.datetime;

Expand Down Expand Up @@ -66,10 +68,10 @@ export function Edit( {
}
}

// Hide and clean date fields if the user manually change
// Hide and clean date fields if the user manually changes
// the sale price to zero or less.
useEffect( () => {
if ( ! isSalePriceGreaterThanZero ) {
if ( hasEdit( 'sale_price' ) && ! isSalePriceGreaterThanZero ) {
setShowScheduleSale( false );
setDateOnSaleFromGmt( '' );
setDateOnSaleToGmt( '' );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ import {
useEntityBlockEditor,
} from '@wordpress/core-data';

/**
* Internal dependencies
*/
import { useConfirmUnsavedProductChanges } from '../../hooks/use-confirm-unsaved-product-changes';

type BlockEditorProps = {
context: {
[ key: string ]: unknown;
Expand All @@ -45,6 +50,8 @@ export function BlockEditor( {
settings: _settings,
product,
}: BlockEditorProps ) {
useConfirmUnsavedProductChanges();

const canUserCreateMedia = useSelect( ( select: typeof WPSelect ) => {
const { canUser } = select( 'core' );
return canUser( 'create', 'media', '' ) !== false;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* External dependencies
*/
import { useSelect } from '@wordpress/data';
import { useConfirmUnsavedChanges } from '@woocommerce/navigation';
import { useEntityProp } from '@wordpress/core-data';

/**
* Internal dependencies
*/
import { preventLeavingProductForm } from '../utils/prevent-leaving-product-form';
import { useProductEdits } from './use-product-edits';

export function useConfirmUnsavedProductChanges() {
const [ productId ] = useEntityProp< number >(
'postType',
'product',
'id'
);
const { hasEdits } = useProductEdits();
const { isSaving } = useSelect(
( select ) => {
const { isSavingEntityRecord } = select( 'core' );

return {
isSaving: isSavingEntityRecord< boolean >(
'postType',
'product',
productId
),
};
},
[ productId ]
);

useConfirmUnsavedChanges( hasEdits || isSaving, preventLeavingProductForm );
}
52 changes: 52 additions & 0 deletions packages/js/product-editor/src/hooks/use-product-edits.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
* External dependencies
*/
import { useEntityProp } from '@wordpress/core-data';
import { useSelect } from '@wordpress/data';

type EntityEdits = {
[ key: string ]: unknown;
};

// Filter out the "content" and "blocks" properties of the edits since
// we do not use these properties within the product editor and they
// will always create false positives.
function filterProductEdits( edits: EntityEdits ) {
delete edits.content;
delete edits.blocks;
return edits;
}

export function useProductEdits() {
const [ productId ] = useEntityProp< number >(
'postType',
'product',
'id'
);

const { edits } = useSelect(
( select ) => {
const { getEntityRecordNonTransientEdits } = select( 'core' );

const _edits = getEntityRecordNonTransientEdits(
'postType',
'product',
productId
) as EntityEdits;

return {
edits: filterProductEdits( _edits ),
};
},
[ productId ]
);

function hasEdit( fieldName: string ) {
return edits.hasOwnProperty( fieldName );
}

return {
hasEdit,
hasEdits: Object.keys( edits ).length > 0,
};
}

0 comments on commit a5e3637

Please sign in to comment.