2023-08-28 01:28:05 +00:00
|
|
|
// Reference: https://github.com/WordPress/gutenberg/blob/v16.4.0/packages/edit-site/src/components/save-hub/index.js
|
|
|
|
/* eslint-disable @woocommerce/dependency-group */
|
|
|
|
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
|
|
|
/**
|
|
|
|
* External dependencies
|
|
|
|
*/
|
2023-10-04 04:16:41 +00:00
|
|
|
import { useContext, useState } from '@wordpress/element';
|
2023-09-12 06:32:50 +00:00
|
|
|
import { useQuery } from '@woocommerce/navigation';
|
2023-08-28 01:28:05 +00:00
|
|
|
import { useSelect, useDispatch } from '@wordpress/data';
|
2023-09-15 04:01:02 +00:00
|
|
|
import {
|
|
|
|
// @ts-ignore No types for this exist yet.
|
|
|
|
__experimentalHStack as HStack,
|
2023-09-20 04:52:22 +00:00
|
|
|
// @ts-ignore No types for this exist yet.
|
|
|
|
__experimentalUseNavigator as useNavigator,
|
2023-09-15 04:01:02 +00:00
|
|
|
Button,
|
|
|
|
Spinner,
|
|
|
|
} from '@wordpress/components';
|
2023-09-05 06:21:19 +00:00
|
|
|
import { __ } from '@wordpress/i18n';
|
2023-08-28 01:28:05 +00:00
|
|
|
// @ts-ignore No types for this exist yet.
|
|
|
|
import { store as coreStore } from '@wordpress/core-data';
|
|
|
|
// @ts-ignore No types for this exist yet.
|
|
|
|
import { store as blockEditorStore } from '@wordpress/block-editor';
|
|
|
|
// @ts-ignore No types for this exist yet.
|
|
|
|
import { store as noticesStore } from '@wordpress/notices';
|
|
|
|
// @ts-ignore No types for this exist yet.
|
2023-09-05 06:21:19 +00:00
|
|
|
import { useEntitiesSavedStatesIsDirty as useIsDirty } from '@wordpress/editor';
|
2023-09-19 03:37:46 +00:00
|
|
|
import { recordEvent } from '@woocommerce/tracks';
|
2023-08-28 01:28:05 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal dependencies
|
|
|
|
*/
|
|
|
|
import { CustomizeStoreContext } from '../';
|
2023-10-05 12:39:24 +00:00
|
|
|
import { HighlightedBlockContext } from '../context/highlighted-block-context';
|
2023-08-28 01:28:05 +00:00
|
|
|
|
|
|
|
const PUBLISH_ON_SAVE_ENTITIES = [
|
|
|
|
{
|
|
|
|
kind: 'postType',
|
|
|
|
name: 'wp_navigation',
|
|
|
|
},
|
|
|
|
];
|
|
|
|
|
|
|
|
export const SaveHub = () => {
|
2023-09-12 06:32:50 +00:00
|
|
|
const urlParams = useQuery();
|
2023-08-28 01:28:05 +00:00
|
|
|
const { sendEvent } = useContext( CustomizeStoreContext );
|
2023-09-15 04:01:02 +00:00
|
|
|
const [ isResolving, setIsResolving ] = useState< boolean >( false );
|
2023-09-20 04:52:22 +00:00
|
|
|
const navigator = useNavigator();
|
2023-10-05 12:39:24 +00:00
|
|
|
const { resetHighlightedBlockIndex } = useContext(
|
|
|
|
HighlightedBlockContext
|
|
|
|
);
|
2023-08-28 01:28:05 +00:00
|
|
|
// @ts-ignore No types for this exist yet.
|
|
|
|
const { __unstableMarkLastChangeAsPersistent } =
|
|
|
|
useDispatch( blockEditorStore );
|
|
|
|
|
2023-10-04 04:16:41 +00:00
|
|
|
const { createErrorNotice } = useDispatch( noticesStore );
|
2023-08-28 01:28:05 +00:00
|
|
|
|
2023-09-05 06:21:19 +00:00
|
|
|
const {
|
|
|
|
dirtyEntityRecords,
|
|
|
|
isDirty,
|
|
|
|
}: {
|
|
|
|
dirtyEntityRecords: {
|
|
|
|
key?: string | number;
|
|
|
|
kind: string;
|
|
|
|
name: string;
|
|
|
|
property?: string;
|
|
|
|
title: string;
|
|
|
|
}[];
|
|
|
|
isDirty: boolean;
|
|
|
|
} = useIsDirty();
|
|
|
|
|
|
|
|
const { isSaving } = useSelect(
|
|
|
|
( select ) => {
|
|
|
|
return {
|
|
|
|
isSaving: dirtyEntityRecords.some( ( record ) =>
|
2023-08-28 01:28:05 +00:00
|
|
|
// @ts-ignore No types for this exist yet.
|
2023-09-05 06:21:19 +00:00
|
|
|
select( coreStore ).isSavingEntityRecord(
|
|
|
|
record.kind,
|
|
|
|
record.name,
|
|
|
|
record.key
|
|
|
|
)
|
|
|
|
),
|
|
|
|
};
|
|
|
|
},
|
|
|
|
[ dirtyEntityRecords ]
|
|
|
|
);
|
2023-08-28 01:28:05 +00:00
|
|
|
|
|
|
|
const {
|
|
|
|
// @ts-ignore No types for this exist yet.
|
|
|
|
editEntityRecord,
|
|
|
|
// @ts-ignore No types for this exist yet.
|
|
|
|
saveEditedEntityRecord,
|
|
|
|
// @ts-ignore No types for this exist yet.
|
|
|
|
__experimentalSaveSpecifiedEntityEdits: saveSpecifiedEntityEdits,
|
|
|
|
} = useDispatch( coreStore );
|
|
|
|
|
2023-10-04 04:16:41 +00:00
|
|
|
const save = async () => {
|
|
|
|
for ( const { kind, name, key, property } of dirtyEntityRecords ) {
|
|
|
|
if ( kind === 'root' && name === 'site' ) {
|
|
|
|
await saveSpecifiedEntityEdits( 'root', 'site', undefined, [
|
|
|
|
property,
|
|
|
|
] );
|
2023-09-05 06:21:19 +00:00
|
|
|
} else {
|
2023-10-04 04:16:41 +00:00
|
|
|
if (
|
|
|
|
PUBLISH_ON_SAVE_ENTITIES.some(
|
|
|
|
( typeToPublish ) =>
|
|
|
|
typeToPublish.kind === kind &&
|
|
|
|
typeToPublish.name === name
|
|
|
|
)
|
|
|
|
) {
|
|
|
|
editEntityRecord( kind, name, key, {
|
|
|
|
status: 'publish',
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
|
|
|
|
await saveEditedEntityRecord( kind, name, key );
|
|
|
|
__unstableMarkLastChangeAsPersistent();
|
2023-09-05 06:21:19 +00:00
|
|
|
}
|
2023-10-04 04:16:41 +00:00
|
|
|
}
|
|
|
|
};
|
2023-08-28 01:28:05 +00:00
|
|
|
|
2023-10-04 04:16:41 +00:00
|
|
|
const onClickSaveButton = async () => {
|
2023-09-19 03:37:46 +00:00
|
|
|
const source = `${ urlParams.path.replace(
|
|
|
|
'/customize-store/assembler-hub/',
|
|
|
|
''
|
|
|
|
) }`;
|
|
|
|
recordEvent( 'customize_your_store_assembler_hub_save_click', {
|
|
|
|
source,
|
|
|
|
} );
|
2023-08-28 01:28:05 +00:00
|
|
|
|
|
|
|
try {
|
2023-10-04 04:16:41 +00:00
|
|
|
await save();
|
2023-10-05 12:39:24 +00:00
|
|
|
resetHighlightedBlockIndex();
|
2023-09-20 04:52:22 +00:00
|
|
|
navigator.goToParent();
|
2023-08-28 01:28:05 +00:00
|
|
|
} catch ( error ) {
|
|
|
|
createErrorNotice(
|
|
|
|
`${ __( 'Saving failed.', 'woocommerce' ) } ${ error }`
|
|
|
|
);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-10-04 04:16:41 +00:00
|
|
|
const onDone = async () => {
|
|
|
|
recordEvent( 'customize_your_store_assembler_hub_done_click' );
|
|
|
|
setIsResolving( true );
|
|
|
|
|
|
|
|
try {
|
|
|
|
await save();
|
|
|
|
sendEvent( 'FINISH_CUSTOMIZATION' );
|
|
|
|
} catch ( error ) {
|
|
|
|
createErrorNotice(
|
|
|
|
`${ __( 'Saving failed.', 'woocommerce' ) } ${ error }`
|
|
|
|
);
|
|
|
|
setIsResolving( false );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-08-28 01:28:05 +00:00
|
|
|
const renderButton = () => {
|
2023-09-12 06:32:50 +00:00
|
|
|
if ( urlParams.path === '/customize-store/assembler-hub' ) {
|
2023-08-28 01:28:05 +00:00
|
|
|
return (
|
|
|
|
<Button
|
|
|
|
variant="primary"
|
2023-10-04 04:16:41 +00:00
|
|
|
onClick={ onDone }
|
2023-08-28 01:28:05 +00:00
|
|
|
className="edit-site-save-hub__button"
|
2023-10-19 14:12:53 +00:00
|
|
|
disabled={ isResolving }
|
|
|
|
aria-disabled={ isResolving }
|
2023-08-28 01:28:05 +00:00
|
|
|
// @ts-ignore No types for this exist yet.
|
|
|
|
__next40pxDefaultSize
|
|
|
|
>
|
2023-09-15 04:01:02 +00:00
|
|
|
{ isResolving ? <Spinner /> : __( 'Done', 'woocommerce' ) }
|
2023-08-28 01:28:05 +00:00
|
|
|
</Button>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-09-05 06:21:19 +00:00
|
|
|
// if we have only one unsaved change and it matches current context, we can show a more specific label
|
|
|
|
const label = isSaving
|
|
|
|
? __( 'Saving', 'woocommerce' )
|
|
|
|
: __( 'Save', 'woocommerce' );
|
|
|
|
|
|
|
|
const isDisabled = ! isDirty || isSaving;
|
|
|
|
|
2023-08-28 01:28:05 +00:00
|
|
|
return (
|
2023-09-05 06:21:19 +00:00
|
|
|
<Button
|
|
|
|
variant="primary"
|
2023-10-04 04:16:41 +00:00
|
|
|
onClick={ onClickSaveButton }
|
2023-09-05 06:21:19 +00:00
|
|
|
disabled={ isDisabled }
|
|
|
|
aria-disabled={ isDisabled }
|
2023-08-28 01:28:05 +00:00
|
|
|
className="edit-site-save-hub__button"
|
2023-09-05 06:21:19 +00:00
|
|
|
// @ts-ignore No types for this exist yet.
|
2023-08-28 01:28:05 +00:00
|
|
|
__next40pxDefaultSize
|
2023-09-05 06:21:19 +00:00
|
|
|
>
|
2023-10-19 14:12:53 +00:00
|
|
|
{ isSaving ? <Spinner /> : label }
|
2023-09-05 06:21:19 +00:00
|
|
|
</Button>
|
2023-08-28 01:28:05 +00:00
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
return (
|
|
|
|
<HStack className="edit-site-save-hub" alignment="right" spacing={ 4 }>
|
|
|
|
{ renderButton() }
|
|
|
|
</HStack>
|
|
|
|
);
|
|
|
|
};
|