diff --git a/modules/store/commerce_store.install b/modules/store/commerce_store.install index 192fe34c..1aacde06 100644 --- a/modules/store/commerce_store.install +++ b/modules/store/commerce_store.install @@ -121,3 +121,26 @@ function commerce_store_update_8205() { $storage_definition->setDefaultValueCallback($default_value_callback); $definition_update_manager->updateFieldStorageDefinition($storage_definition); } + +/** + * Add created and changed fields to stores. + */ +function commerce_store_update_8206() { + $definition_update_manager = \Drupal::entityDefinitionUpdateManager(); + + $storage_definitions['created'] = BaseFieldDefinition::create('created') + ->setLabel(t('Created')) + ->setDescription(t('The time when the store was created.')) + ->setTranslatable(TRUE) + ->setDisplayConfigurable('form', TRUE) + ->setDisplayConfigurable('view', TRUE); + + $storage_definitions['changed'] = BaseFieldDefinition::create('changed') + ->setLabel(t('Changed')) + ->setDescription(t('The time when the store was last edited.')) + ->setTranslatable(TRUE); + + foreach ($storage_definitions as $name => $definition) { + $definition_update_manager->installFieldStorageDefinition($name, 'commerce_store', 'commerce_store', $definition); + } +} diff --git a/modules/store/commerce_store.libraries.yml b/modules/store/commerce_store.libraries.yml new file mode 100644 index 00000000..153f7ed2 --- /dev/null +++ b/modules/store/commerce_store.libraries.yml @@ -0,0 +1,5 @@ +form: + version: VERSION + css: + theme: + css/store.form.css: {} diff --git a/modules/store/commerce_store.module b/modules/store/commerce_store.module index 761bd8a4..3ca225be 100644 --- a/modules/store/commerce_store.module +++ b/modules/store/commerce_store.module @@ -32,6 +32,9 @@ function commerce_store_theme() { 'commerce_store' => [ 'render element' => 'elements', ], + 'commerce_store_form' => [ + 'render element' => 'form', + ], ]; } diff --git a/modules/store/config/install/views.view.commerce_stores.yml b/modules/store/config/install/views.view.commerce_stores.yml index 9bb353a3..9561899a 100644 --- a/modules/store/config/install/views.view.commerce_stores.yml +++ b/modules/store/config/install/views.view.commerce_stores.yml @@ -78,12 +78,16 @@ display: description: '' columns: name: name + changed: changed type: type operations: operations info: name: sortable: true default_sort_order: asc + changed: + sortable: true + default_sort_order: desc align: '' separator: '' empty_column: false @@ -225,6 +229,73 @@ display: entity_type: null entity_field: name plugin_id: field + changed: + id: changed + table: commerce_store_field_data + field: changed + relationship: none + group_type: group + admin_label: '' + label: Updated + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: timestamp + settings: + date_format: short + custom_date_format: '' + timezone: '' + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: commerce_store + entity_field: changed + plugin_id: field type: id: type table: commerce_store_field_data diff --git a/modules/store/css/store.form.css b/modules/store/css/store.form.css new file mode 100644 index 00000000..99ce5c95 --- /dev/null +++ b/modules/store/css/store.form.css @@ -0,0 +1,59 @@ +/** + * @file + * Styles for the store add/edit form. + * + * Copied from node-module.css + */ + +/* Narrow screens */ +.layout-region { + box-sizing: border-box; +} + +/* Wide screens */ +@media +screen and (min-width: 780px), +(orientation: landscape) and (min-device-height: 780px) { + + .layout-region-store-main, + .layout-region-store-footer { + float: left; /* LTR */ + width: 65%; + padding-right: 2em; /* LTR */ + box-sizing: border-box; + } + + [dir="rtl"] .layout-region-store-main, + [dir="rtl"] .layout-region-store-footer { + float: right; + padding-left: 2em; + padding-right: 0; + } + + .layout-region-store-secondary { + float: right; /* LTR */ + width: 35%; + } + + [dir="rtl"] .layout-region-store-secondary { + float: left; + } +} + +/** + * The vertical toolbar mode gets triggered for narrow screens, which throws off + * the intent of media queries written for the viewport width. When the vertical + * toolbar is on, we need to suppress layout for the original media width + the + * toolbar width (240px). In this case, 240px + 780px. + */ +@media +screen and (max-width: 1020px) { + + .toolbar-vertical.toolbar-tray-open .layout-region-store-main, + .toolbar-vertical.toolbar-tray-open .layout-region-store-footer, + .toolbar-vertical.toolbar-tray-open .layout-region-store-secondary { + float: none; + width: auto; + padding-right: 0; + } +} diff --git a/modules/store/src/Entity/Store.php b/modules/store/src/Entity/Store.php index 05539713..d0617095 100644 --- a/modules/store/src/Entity/Store.php +++ b/modules/store/src/Entity/Store.php @@ -11,6 +11,7 @@ use Drupal\Core\Entity\ContentEntityBase; use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Field\BaseFieldDefinition; +use Drupal\Core\Entity\EntityChangedTrait; /** * Defines the store entity class. @@ -83,6 +84,7 @@ use Drupal\Core\Field\BaseFieldDefinition; class Store extends ContentEntityBase implements StoreInterface { use EntityOwnerTrait; + use EntityChangedTrait; /** * {@inheritdoc} @@ -228,6 +230,21 @@ class Store extends ContentEntityBase implements StoreInterface { } } + /** + * {@inheritdoc} + */ + public function getCreatedTime() { + return $this->get('created')->value; + } + + /** + * {@inheritdoc} + */ + public function setCreatedTime($timestamp) { + $this->set('created', $timestamp); + return $this; + } + /** * {@inheritdoc} */ @@ -385,6 +402,18 @@ class Store extends ContentEntityBase implements StoreInterface { ->setDisplayConfigurable('view', TRUE) ->setDisplayConfigurable('form', TRUE); + $fields['created'] = BaseFieldDefinition::create('created') + ->setLabel(t('Created')) + ->setDescription(t('The time when the store was created.')) + ->setTranslatable(TRUE) + ->setDisplayConfigurable('form', TRUE) + ->setDisplayConfigurable('view', TRUE); + + $fields['changed'] = BaseFieldDefinition::create('changed') + ->setLabel(t('Changed')) + ->setDescription(t('The time when the store was last edited.')) + ->setTranslatable(TRUE); + return $fields; } diff --git a/modules/store/src/Entity/StoreInterface.php b/modules/store/src/Entity/StoreInterface.php index 172e6139..44825f22 100644 --- a/modules/store/src/Entity/StoreInterface.php +++ b/modules/store/src/Entity/StoreInterface.php @@ -6,11 +6,12 @@ use Drupal\address\AddressInterface; use Drupal\commerce_price\Entity\CurrencyInterface; use Drupal\Core\Entity\ContentEntityInterface; use Drupal\user\EntityOwnerInterface; +use Drupal\Core\Entity\EntityChangedInterface; /** * Defines the interface for stores. */ -interface StoreInterface extends ContentEntityInterface, EntityOwnerInterface { +interface StoreInterface extends ContentEntityInterface, EntityOwnerInterface, EntityChangedInterface { /** * Gets the store name. @@ -160,4 +161,22 @@ interface StoreInterface extends ContentEntityInterface, EntityOwnerInterface { */ public function setDefault($is_default); + /** + * Gets the store creation timestamp. + * + * @return int + * The store creation timestamp. + */ + public function getCreatedTime(); + + /** + * Sets the store creation timestamp. + * + * @param int $timestamp + * The store creation timestamp. + * + * @return $this + */ + public function setCreatedTime($timestamp); + } diff --git a/modules/store/src/Form/StoreForm.php b/modules/store/src/Form/StoreForm.php index f3273064..ca6f8e72 100644 --- a/modules/store/src/Form/StoreForm.php +++ b/modules/store/src/Form/StoreForm.php @@ -5,11 +5,28 @@ namespace Drupal\commerce_store\Form; use Drupal\Core\Entity\ContentEntityForm; use Drupal\Core\Form\FormStateInterface; use Drupal\entity\Form\EntityDuplicateFormTrait; +use Symfony\Component\DependencyInjection\ContainerInterface; class StoreForm extends ContentEntityForm { use EntityDuplicateFormTrait; + /** + * The date formatter. + * + * @var \Drupal\Core\Datetime\DateFormatterInterface + */ + protected $dateFormatter; + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + $instance = parent::create($container); + $instance->dateFormatter = $container->get('date.formatter'); + return $instance; + } + /** * {@inheritdoc} */ @@ -18,6 +35,77 @@ class StoreForm extends ContentEntityForm { /** @var \Drupal\commerce_store\Entity\StoreInterface $store */ $store = $this->entity; + $form['#theme'] = ['commerce_store_form']; + $form['#attached']['library'][] = 'commerce_store/form'; + $changed = $store->getChangedTime(); + $form['changed'] = [ + '#type' => 'hidden', + '#default_value' => $changed, + ]; + if ($changed) { + $last_saved = $this->dateFormatter->format($changed, 'short'); + } + else { + $last_saved = $store->isNew() ? $this->t('Not saved yet') : $this->t('N/A'); + } + + $form['advanced'] = [ + '#type' => 'container', + '#attributes' => ['class' => ['entity-meta']], + '#weight' => 99, + ]; + $form['meta'] = [ + '#attributes' => ['class' => ['entity-meta__header']], + '#type' => 'container', + '#group' => 'advanced', + '#title' => $this->t('Authoring information'), + '#weight' => 90, + 'published' => [ + '#type' => 'html_tag', + '#tag' => 'h3', + '#value' => $store->isDefault() ? $this->t('Default store') : '', + '#access' => $store->isDefault(), + '#attributes' => [ + 'class' => ['entity-meta__title'], + ], + ], + 'changed' => [ + '#type' => 'item', + '#wrapper_attributes' => [ + 'class' => ['entity-meta__last-saved', 'container-inline'], + ], + '#markup' => '

' . $this->t('Last saved') . '

' . $last_saved, + ], + 'owner' => [ + '#type' => 'item', + '#wrapper_attributes' => [ + 'class' => ['author', 'container-inline'], + ], + '#markup' => '

' . $this->t('Owner') . '

' . $store->getOwner()->getDisplayName(), + ], + ]; + if (isset($form['uid'])) { + $form['uid']['#group'] = 'author'; + } + if (isset($form['created'])) { + $form['created']['#group'] = 'author'; + } + $form['countries'] = [ + '#type' => 'details', + '#title' => t('Supported countries'), + '#weight' => 90, + '#open' => TRUE, + '#group' => 'advanced', + ]; + if (isset($form['billing_countries'])) { + $form['billing_countries']['widget']['#title'] = $this->t('Billing countries'); + $form['billing_countries']['#group'] = 'countries'; + } + if (isset($form['shipping_countries'])) { + $form['shipping_countries']['widget']['#title'] = $this->t('Shipping countries'); + $form['shipping_countries']['#group'] = 'countries'; + } + $form['path_settings'] = [ '#type' => 'details', '#title' => $this->t('URL path settings'), diff --git a/modules/store/templates/commerce-store-form.html.twig b/modules/store/templates/commerce-store-form.html.twig new file mode 100644 index 00000000..6f38f2ab --- /dev/null +++ b/modules/store/templates/commerce-store-form.html.twig @@ -0,0 +1,22 @@ +{# +/** + * @file + * Template for the store add/edit form. + * + * Available variables: + * - form: The form. + * + * @ingroup themeable + */ +#} +
+
+ {{ form|without('advanced', 'actions') }} +
+
+ {{ form.advanced }} +
+ +
diff --git a/modules/tax/commerce_tax.module b/modules/tax/commerce_tax.module index 96132d3c..1a90f3c2 100644 --- a/modules/tax/commerce_tax.module +++ b/modules/tax/commerce_tax.module @@ -81,6 +81,7 @@ function commerce_tax_form_commerce_store_form_alter(&$form, FormStateInterface '#title' => t('Tax settings'), '#weight' => 90, '#open' => TRUE, + '#group' => 'advanced', ]; $form['prices_include_tax']['#group'] = 'tax_settings'; $form['tax_registrations']['#group'] = 'tax_settings';