From 277fa6b00540739aaaacc08165e86a07f45ab6d7 Mon Sep 17 00:00:00 2001 From: Maikel Perez Date: Mon, 11 Mar 2024 15:28:51 -0300 Subject: [PATCH] Edit Custom Fields for New Product Editor (#45396) * Create edit modal * Add update function to the useCustomFields hook * Integrate the EditModal in the CustomFields component * Add edition and validation logic to the custom field EditModal component * Fix text control validation error styles * Focus the name field when its invalid * Fix linter error * Fix edit modal min width and controls width * Add changelog file * Fix text overflow in custom fields table * Remove non needed block style file --- .../product-editor/changelog/add-44169-edit | 4 + .../product-fields/custom-fields/block.json | 4 +- .../product-fields/custom-fields/editor.scss | 2 - .../js/product-editor/src/blocks/style.scss | 1 - .../custom-fields/custom-fields.tsx | 105 +++++++++++------ .../custom-fields/edit-modal/edit-modal.tsx | 106 ++++++++++++++++++ .../custom-fields/edit-modal/index.ts | 2 + .../custom-fields/edit-modal/style.scss | 15 +++ .../custom-fields/edit-modal/types.ts | 18 +++ .../src/components/custom-fields/style.scss | 4 +- .../src/components/text-control/style.scss | 12 ++ .../components/text-control/text-control.tsx | 10 +- .../use-custom-fields/use-custom-fields.ts | 13 ++- packages/js/product-editor/src/style.scss | 1 + 14 files changed, 254 insertions(+), 43 deletions(-) create mode 100644 packages/js/product-editor/changelog/add-44169-edit delete mode 100644 packages/js/product-editor/src/blocks/product-fields/custom-fields/editor.scss create mode 100644 packages/js/product-editor/src/components/custom-fields/edit-modal/edit-modal.tsx create mode 100644 packages/js/product-editor/src/components/custom-fields/edit-modal/index.ts create mode 100644 packages/js/product-editor/src/components/custom-fields/edit-modal/style.scss create mode 100644 packages/js/product-editor/src/components/custom-fields/edit-modal/types.ts create mode 100644 packages/js/product-editor/src/components/text-control/style.scss diff --git a/packages/js/product-editor/changelog/add-44169-edit b/packages/js/product-editor/changelog/add-44169-edit new file mode 100644 index 00000000000..2312ba32796 --- /dev/null +++ b/packages/js/product-editor/changelog/add-44169-edit @@ -0,0 +1,4 @@ +Significance: minor +Type: add + +Edit Custom Fields for New Product Editor diff --git a/packages/js/product-editor/src/blocks/product-fields/custom-fields/block.json b/packages/js/product-editor/src/blocks/product-fields/custom-fields/block.json index d5932e0004b..73824721fe2 100644 --- a/packages/js/product-editor/src/blocks/product-fields/custom-fields/block.json +++ b/packages/js/product-editor/src/blocks/product-fields/custom-fields/block.json @@ -21,7 +21,5 @@ "inserter": false, "lock": false, "__experimentalToolbar": false - }, - "usesContext": [ "postType" ], - "editorStyle": "file:./editor.css" + } } diff --git a/packages/js/product-editor/src/blocks/product-fields/custom-fields/editor.scss b/packages/js/product-editor/src/blocks/product-fields/custom-fields/editor.scss deleted file mode 100644 index 2ff3974413d..00000000000 --- a/packages/js/product-editor/src/blocks/product-fields/custom-fields/editor.scss +++ /dev/null @@ -1,2 +0,0 @@ -.wp-block-woocommerce-product-custom-fields-field { -} diff --git a/packages/js/product-editor/src/blocks/style.scss b/packages/js/product-editor/src/blocks/style.scss index 7099f75bd10..29502c134b0 100644 --- a/packages/js/product-editor/src/blocks/style.scss +++ b/packages/js/product-editor/src/blocks/style.scss @@ -1,7 +1,6 @@ @import "product-fields/attributes/editor.scss"; @import "product-fields/description/editor.scss"; @import "product-fields/catalog-visibility/editor.scss"; -@import "product-fields/custom-fields/editor.scss"; @import "product-fields/custom-fields-toggle/editor.scss"; @import "product-fields/downloads/editor.scss"; @import "product-fields/images/editor.scss"; diff --git a/packages/js/product-editor/src/components/custom-fields/custom-fields.tsx b/packages/js/product-editor/src/components/custom-fields/custom-fields.tsx index ef30ecac777..08412d972f8 100644 --- a/packages/js/product-editor/src/components/custom-fields/custom-fields.tsx +++ b/packages/js/product-editor/src/components/custom-fields/custom-fields.tsx @@ -1,7 +1,8 @@ /** * External dependencies */ -import { createElement } from '@wordpress/element'; +import { Button } from '@wordpress/components'; +import { createElement, Fragment, useState } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; import classNames from 'classnames'; @@ -9,47 +10,87 @@ import classNames from 'classnames'; * Internal dependencies */ import { useCustomFields } from '../../hooks/use-custom-fields'; +import { EditModal } from './edit-modal'; import { EmptyState } from './empty-state'; +import type { Metadata } from '../../types'; import type { CustomFieldsProps } from './types'; export function CustomFields( { className, ...props }: CustomFieldsProps ) { - const { customFields } = useCustomFields(); + const { customFields, updateCustomField } = useCustomFields(); + const [ selectedCustomField, setSelectedCustomField ] = + useState< Metadata< string > >(); if ( customFields.length === 0 ) { return ; } + function customFieldEditButtonClickHandler( + customField: Metadata< string > + ) { + return function handleCustomFieldEditButtonClick() { + setSelectedCustomField( customField ); + }; + } + + function handleEditModalUpdate( customField: Metadata< string > ) { + updateCustomField( customField ); + setSelectedCustomField( undefined ); + } + + function handleEditModalCancel() { + setSelectedCustomField( undefined ); + } + return ( - - - - - - - - - - { customFields.map( ( customField ) => ( - - - - + <> +
{ __( 'Name', 'woocommerce' ) }{ __( 'Value', 'woocommerce' ) }{ __( 'Actions', 'woocommerce' ) }
- { customField.key } - - { customField.value } -
+ + + + + - ) ) } - -
{ __( 'Name', 'woocommerce' ) }{ __( 'Value', 'woocommerce' ) }{ __( 'Actions', 'woocommerce' ) }
+ + + { customFields.map( ( customField ) => ( + + + { customField.key } + + + { customField.value } + + + + + + ) ) } + + + + { selectedCustomField && ( + + ) } + ); } diff --git a/packages/js/product-editor/src/components/custom-fields/edit-modal/edit-modal.tsx b/packages/js/product-editor/src/components/custom-fields/edit-modal/edit-modal.tsx new file mode 100644 index 00000000000..634fc7f6d94 --- /dev/null +++ b/packages/js/product-editor/src/components/custom-fields/edit-modal/edit-modal.tsx @@ -0,0 +1,106 @@ +/** + * External dependencies + */ +import { Button, Modal } from '@wordpress/components'; +import { createElement, useState, useRef } from '@wordpress/element'; +import { __, sprintf } from '@wordpress/i18n'; +import classNames from 'classnames'; +import type { FocusEvent } from 'react'; + +/** + * Internal dependencies + */ +import { TextControl } from '../../text-control'; +import type { Metadata } from '../../../types'; +import type { EditModalProps } from './types'; + +function validateName( value: string ) { + if ( value.startsWith( '_' ) ) { + return __( + 'The name cannot begin with the underscore (_) character.', + 'woocommerce' + ); + } +} + +export function EditModal( { + initialValue, + onUpdate, + onCancel, + ...props +}: EditModalProps ) { + const [ customField, setCustomField ] = + useState< Metadata< string > >( initialValue ); + const [ validationError, setValidationError ] = useState< string >(); + const nameTextRef = useRef< HTMLInputElement >( null ); + + function renderTitle() { + return sprintf( + /* translators: %s: the name of the custom field */ + __( 'Edit %s', 'woocommerce' ), + customField.key + ); + } + + function handleNameChange( key: string ) { + setCustomField( ( current ) => ( { ...current, key } ) ); + } + + function handleNameBlur( event: FocusEvent< HTMLInputElement > ) { + const error = validateName( event.target.value ); + setValidationError( error ); + } + + function handleValueChange( value: string ) { + setCustomField( ( current ) => ( { ...current, value } ) ); + } + + function handleUpdateButtonClick() { + const error = validateName( customField.key ); + if ( error ) { + setValidationError( error ); + nameTextRef.current?.focus(); + return; + } + + onUpdate( customField ); + } + + return ( + + + + + +
+ + + +
+
+ ); +} diff --git a/packages/js/product-editor/src/components/custom-fields/edit-modal/index.ts b/packages/js/product-editor/src/components/custom-fields/edit-modal/index.ts new file mode 100644 index 00000000000..1983e31d98a --- /dev/null +++ b/packages/js/product-editor/src/components/custom-fields/edit-modal/index.ts @@ -0,0 +1,2 @@ +export * from './edit-modal'; +export * from './types'; diff --git a/packages/js/product-editor/src/components/custom-fields/edit-modal/style.scss b/packages/js/product-editor/src/components/custom-fields/edit-modal/style.scss new file mode 100644 index 00000000000..5818569d744 --- /dev/null +++ b/packages/js/product-editor/src/components/custom-fields/edit-modal/style.scss @@ -0,0 +1,15 @@ +.woocommerce-product-custom-fields__edit-modal { + min-width: 75%; + + &-actions { + display: flex; + align-items: center; + justify-content: flex-end; + gap: 12px; + margin-top: $grid-unit-40; + } + + .components-base-control { + width: 100%; + } +} diff --git a/packages/js/product-editor/src/components/custom-fields/edit-modal/types.ts b/packages/js/product-editor/src/components/custom-fields/edit-modal/types.ts new file mode 100644 index 00000000000..ac325182ec4 --- /dev/null +++ b/packages/js/product-editor/src/components/custom-fields/edit-modal/types.ts @@ -0,0 +1,18 @@ +/** + * External dependencies + */ +import { Modal } from '@wordpress/components'; + +/** + * Internal dependencies + */ +import { Metadata } from '../../../types'; + +export type EditModalProps = Omit< + Modal.Props, + 'title' | 'onRequestClose' | 'children' +> & { + initialValue: Metadata< string >; + onUpdate( value: Metadata< string > ): void; + onCancel(): void; +}; diff --git a/packages/js/product-editor/src/components/custom-fields/style.scss b/packages/js/product-editor/src/components/custom-fields/style.scss index ffd20e40704..01c3efb1fca 100644 --- a/packages/js/product-editor/src/components/custom-fields/style.scss +++ b/packages/js/product-editor/src/components/custom-fields/style.scss @@ -1,4 +1,5 @@ @import "./empty-state/style.scss"; +@import "./edit-modal/style.scss"; .woocommerce-product-custom-fields { &__table { @@ -22,12 +23,13 @@ &-datacell { padding-top: $grid-unit-30; padding-bottom: $grid-unit-30; + overflow: hidden; &:last-child { display: flex; align-items: center; justify-content: flex-end; - padding: 0; + padding: 0 2px 0 0; gap: $grid-unit; } } diff --git a/packages/js/product-editor/src/components/text-control/style.scss b/packages/js/product-editor/src/components/text-control/style.scss new file mode 100644 index 00000000000..1ed4fa172fe --- /dev/null +++ b/packages/js/product-editor/src/components/text-control/style.scss @@ -0,0 +1,12 @@ +.woocommerce-product-text-control { + &.has-error { + .components-input-control__container + .components-input-control__backdrop { + border-color: $studio-red-50; + } + + .components-base-control__help { + color: $studio-red-50; + } + } +} diff --git a/packages/js/product-editor/src/components/text-control/text-control.tsx b/packages/js/product-editor/src/components/text-control/text-control.tsx index 1fc71d829a1..19cc06bafff 100644 --- a/packages/js/product-editor/src/components/text-control/text-control.tsx +++ b/packages/js/product-editor/src/components/text-control/text-control.tsx @@ -33,9 +33,13 @@ export const TextControl = forwardRef( function ForwardedTextControl( + current.map( ( field ) => { + if ( customField.id && field.id === customField.id ) { + return customField; + } + return field; + } ) + ); + } + + return { customFields, setCustomFields, updateCustomField }; } diff --git a/packages/js/product-editor/src/style.scss b/packages/js/product-editor/src/style.scss index 598ab494058..a3de9b2d224 100644 --- a/packages/js/product-editor/src/style.scss +++ b/packages/js/product-editor/src/style.scss @@ -49,6 +49,7 @@ @import "components/require-password/styles.scss"; @import "components/schedule-publish-modal/style.scss"; @import "components/custom-fields/style.scss"; +@import "components/text-control/style.scss"; /* Field Blocks */