diff --git a/README.md b/README.md deleted file mode 100644 index ba16dde..0000000 --- a/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# D-comm_setup_wiz -Wizard to improve initial setup of Drupal 8 commerce 2.x https://www.drupal.org/node/2878968 diff --git a/modules/contrib/commerce/modules/wizard/commerce_wizard.info.yml b/modules/contrib/commerce/modules/wizard/commerce_wizard.info.yml new file mode 100644 index 0000000..075d4c8 --- /dev/null +++ b/modules/contrib/commerce/modules/wizard/commerce_wizard.info.yml @@ -0,0 +1,7 @@ +name: Commerce Wizard +type: module +description: 'Provides a quick installation method for drupal commerce.' +package: Commerce +dependencies: + - commerce +core: 8.x diff --git a/modules/contrib/commerce/modules/wizard/commerce_wizard.libraries.yml b/modules/contrib/commerce/modules/wizard/commerce_wizard.libraries.yml new file mode 100644 index 0000000..bdabdbb --- /dev/null +++ b/modules/contrib/commerce/modules/wizard/commerce_wizard.libraries.yml @@ -0,0 +1,16 @@ +wizard_intro: + version: VERSION + css: + layout: + css/commerce_wizard.layout.css: {} + +wizard_form: + version: VERSION + css: + component: + css/commerce_wizard.component.css: {} + js: + js/commerce_wizard.js: {} + dependencies: + - core/jquery + - core/drupal diff --git a/modules/contrib/commerce/modules/wizard/commerce_wizard.links.menu.yml b/modules/contrib/commerce/modules/wizard/commerce_wizard.links.menu.yml new file mode 100644 index 0000000..e6f5983 --- /dev/null +++ b/modules/contrib/commerce/modules/wizard/commerce_wizard.links.menu.yml @@ -0,0 +1,6 @@ +commerce.commerce_wizard: + title: 'Commerce Setup' + description: 'Quick Installation Method.' + parent: 'commerce.admin_commerce' + route_name: 'commerce.commerce_wizard' + weight: 100 diff --git a/modules/contrib/commerce/modules/wizard/commerce_wizard.module b/modules/contrib/commerce/modules/wizard/commerce_wizard.module new file mode 100644 index 0000000..3963a2e --- /dev/null +++ b/modules/contrib/commerce/modules/wizard/commerce_wizard.module @@ -0,0 +1,60 @@ + [ + 'variables' => [ + 'intro_title' => NULL, + 'intro_text' => NULL, + ], + ], 'stepper' => [ + 'render element' => 'element', + 'template' => 'stepper', + 'variables' => [ + 'title' => NULL, + 'attributes' => NULL, + 'children' => NULL, + 'value' => NULL, + 'required' => NULL, + 'errors' => NULL, + 'open' => FALSE, + 'change_link' => TRUE, + 'button_text' => NULL, + 'skip_text' => NULL, + ], + ], + ]; + + return $variables; + +} + +/** + * Prepares variables for details element templates. + * + * Default template: details.html.twig. + */ +function commerce_wizard_stepper(&$variables) { + $element = $variables['element']; + $variables['attributes'] = $element['#attributes']; + + $variables['title'] = (!empty($element['#title'])) ? $element['#title'] : ''; + $variables['children'] = (isset($element['#children'])) ? $element['#children'] : ''; + $variables['value'] = (isset($element['#value'])) ? $element['#value'] : ''; + $variables['required'] = !empty($element['#required']) ? $element['#required'] : NULL; + + $variables['change_link'] = (isset($element['#change_link'])) ? $element['#change_link'] : ''; + $variables['button_text'] = (isset($element['#button_text'])) ? $element['#button_text'] : ''; + $variables['skip_text'] = (isset($element['#skip_text'])) ? $element['#skip_text'] : ''; + + // Suppress error messages. + $variables['errors'] = NULL; +} diff --git a/modules/contrib/commerce/modules/wizard/commerce_wizard.routing.yml b/modules/contrib/commerce/modules/wizard/commerce_wizard.routing.yml new file mode 100644 index 0000000..2b56c3d --- /dev/null +++ b/modules/contrib/commerce/modules/wizard/commerce_wizard.routing.yml @@ -0,0 +1,15 @@ +commerce.commerce_wizard: + path: '/admin/commerce/wizard' + defaults: + _controller: 'Drupal\commerce_wizard\Controller\WizardController::content' + _title: 'Wizard' + requirements: + _permission: 'access commerce administration pages' + +commerce.commerce_wizard.install: + path: '/admin/commerce/wizard/install' + defaults: + _form: '\Drupal\commerce_wizard\Form\WizardForm' + _title: 'Wizard: Install' + requirements: + _permission: 'access content' diff --git a/modules/contrib/commerce/modules/wizard/css/commerce_wizard.component.css b/modules/contrib/commerce/modules/wizard/css/commerce_wizard.component.css new file mode 100644 index 0000000..eecdfe9 --- /dev/null +++ b/modules/contrib/commerce/modules/wizard/css/commerce_wizard.component.css @@ -0,0 +1,69 @@ +.stepper { + padding: 1em 0; + border-bottom: 1px solid #ccc; +} +.stepper--last { + margin-bottom: 2.5em; +} + +.stepper__header { + padding: .25em 0; + font-size: 1.35em; + display: table; + width: 100%; +} +.stepper__header--title { + color: #666; + width: 75%; + display: table-cell; + vertical-align: top; +} +.stepper__header--skipped { + font-size: .75em; + text-align: right; + width: 25%; + display: table-cell; + vertical-align: top; +} +.stepper__header--button { + font-size: .75em; + display: none; +} + +.stepper__content { + height: 0; + overflow: hidden; + display: none; +} + +/* active state */ +.stepper--active .stepper__content { + padding: 0; + display: block; + height: auto; +} +.stepper--active .stepper__actions { + margin-top: 1.5em; +} +.stepper--active .stepper__header--title { + color: #333; +} + +/* completed state */ +.stepper--complete .stepper__header--title { + color: #325e1c; +} +.stepper--complete .stepper__header--button, +.stepper--complete .stepper__icon { + display: inline-block; +} + +/* icons */ +.stepper__icon { + display: none; + margin: 0 10px 0 5px; + width: 15px; + height: 15px; + background: url(../images/check.svg) no-repeat; + background-size: 15px 15px; +} diff --git a/modules/contrib/commerce/modules/wizard/css/commerce_wizard.layout.css b/modules/contrib/commerce/modules/wizard/css/commerce_wizard.layout.css new file mode 100644 index 0000000..9ad9729 --- /dev/null +++ b/modules/contrib/commerce/modules/wizard/css/commerce_wizard.layout.css @@ -0,0 +1,10 @@ +.commerce__wizard--intro ol { + margin-top: 2em; + margin-bottom: 2em; + margin-left: 1em; + font-size: 1.125em; + line-height: 1.75em; +} +.commerce__wizard--intro ol li { + margin-bottom: 1.25em; +} diff --git a/modules/contrib/commerce/modules/wizard/images/check.svg b/modules/contrib/commerce/modules/wizard/images/check.svg new file mode 100644 index 0000000..8fcb688 --- /dev/null +++ b/modules/contrib/commerce/modules/wizard/images/check.svg @@ -0,0 +1 @@ + diff --git a/modules/contrib/commerce/modules/wizard/js/commerce_wizard.js b/modules/contrib/commerce/modules/wizard/js/commerce_wizard.js new file mode 100644 index 0000000..80c5f33 --- /dev/null +++ b/modules/contrib/commerce/modules/wizard/js/commerce_wizard.js @@ -0,0 +1,128 @@ +/** + * @file + * Defines functionality for the wizard's stepping system. + */ + +(function ($, Drupal, drupalSettings) { + 'use strict'; + + var Steps = []; + + var Stepper = { + + // Init constructor. + init: function (step) { + this.step = step; + this.id = step.attr('id'); + this.next_step = step.next(); + this.next_steps = step.nextAll('.stepper'); + this.submit_button = step.find('.stepper__actions .button--primary'); + }, + + // Helper function to open up the step to the active state. + open: function () { + + var form_submit_button = $('.form-actions .form-submit'); + + // Set the proper classes for showing the active state and remove any old classes. + this.step.addClass('stepper--active').removeClass('stepper--complete'); + + // Hide the skipped button if this step is active. + this.step.find('.stepper__header--skipped').addClass('visually-hidden'); + + // Make sure all steps below are set to inactive. + this.next_steps.each(function () { + var _this = $(this); + _this = $('#' + _this.attr('id')); + _this.removeClass('stepper--active stepper--complete'); + }); + + // Enable/disabled the main form submit. + // Depending on if were on the last step or not. + if (this.step.hasClass('stepper--last')) { + form_submit_button.removeClass('is-disabled').removeAttr('disabled'); + } +else { + form_submit_button.addClass('is-disabled').attr('disabled', 'disabled'); + } + + }, + + // Helper function to complete a step. + // Should mainly be used in the submit function. + complete: function () { + var next_step_id = this.next_step.attr('id'); + + // Close the current step and set it to complete state. + this.step.addClass('stepper--complete').removeClass('stepper--active'); + + // Open the next step, and perform the ajax submit in the step we're closing. + window.Steps[next_step_id].open(); + this.submit_button.mousedown(); + }, + + submit: function () { + // @Todo: setup some js validation in here + this.complete(); + }, + + }; + + // Document ready. + $(document).ready(function () { + + var step = $('.stepper'); + var first_step = step.first(); + var last_step = step.last(); + + // Get all the steps so we can create their objects. + step.each(function () { + var _this = $(this); + var id = $(this).attr('id'); + + // Add the step object for later use. + Steps[id] = Object.create(Stepper); + Steps[id].init(_this); + }); + window.Steps = Steps; + + // Open the first step + // add a class to the last step. + window.Steps[first_step.attr('id')].open(); + last_step.addClass('stepper--last'); + + // Edit buttons. + $('.stepper__header--button').click(function (e) { + e.preventDefault(); + var step_id = $(this).parents('.stepper').attr('id'); + window.Steps[step_id].open(); + }); + + // Steps primary button. + $('.stepper__actions .button--primary').click(function (e) { + e.preventDefault(); + var _this = $(this); + var step_id = _this.parents('.stepper').attr('id'); + + if (!_this.hasClass('is-disabled')) { + window.Steps[step_id].submit(); + } + }); + + // Steps secondary button. + $('.stepper__actions .button--danger').click(function (e) { + e.preventDefault(); + var _this = $(this); + var step_id = _this.parents('.stepper').attr('id'); + + // Show the skipped text. + $('#' + step_id).find('.stepper__header--skipped').removeClass('visually-hidden'); + + if (!_this.hasClass('is-disabled')) { + window.Steps[step_id].submit(); + } + }); + + }); + +})(jQuery, Drupal, drupalSettings); diff --git a/modules/contrib/commerce/modules/wizard/src/Controller/WizardController.php b/modules/contrib/commerce/modules/wizard/src/Controller/WizardController.php new file mode 100644 index 0000000..61b8e71 --- /dev/null +++ b/modules/contrib/commerce/modules/wizard/src/Controller/WizardController.php @@ -0,0 +1,29 @@ + 'commerce_wizard', + '#title' => $this->t('Commerce: Quick Install'), + '#intro_title' => $this->t('Hey! It looks like this is your first time using drupal commerce.'), + '#intro_text' => $this->t('Lets take a few minutes to get your store setup and configured, or skip the setup wizard if you plan to configure your store manually.', ['@url' => '#']), + '#attached' => [ + 'library' => [ + 'commerce_wizard/wizard_intro', + ], + ], + ]; + } + +} diff --git a/modules/contrib/commerce/modules/wizard/src/Element/Stepper.php b/modules/contrib/commerce/modules/wizard/src/Element/Stepper.php new file mode 100644 index 0000000..5a7927e --- /dev/null +++ b/modules/contrib/commerce/modules/wizard/src/Element/Stepper.php @@ -0,0 +1,67 @@ + FALSE, + '#value' => NULL, + '#process' => [[$class, 'processGroup'], [$class, 'processAjaxForm']], + '#pre_render' => [ + [$class, 'preRenderStepper'], + [$class, 'preRenderGroup'], + ], + '#theme_wrappers' => ['stepper'], + '#attached' => [ + 'library' => ['commerce_wizard/wizard_form'], + ], + ]; + } + + /** + * Adds form element theming to details. + * + * Associative array containing the properties and children of the details. + */ + public static function preRenderStepper($element) { + Element::setAttributes($element, ['id']); + + // The .js-form-wrapper class is required for #states to treat details like. + // containers. + static::setAttributes($element, ['js-form-wrapper', 'form-wrapper']); + $element['#attributes']['class'] = 'stepper'; + + // Collapsible details. + $element['#attached']['library'][] = 'core/drupal.collapse'; + + // Open the detail if specified or if a child has an error. + if (!empty($element['#open']) || !empty($element['#children_errors'])) { + $element['#attributes']['class'] .= ' stepper--active'; + } + + // Do not render optional details elements if there are no children. + if (isset($element['#parents'])) { + $group = implode('][', $element['#parents']); + if (!empty($element['#optional']) && !Element::getVisibleChildren($element['#groups'][$group])) { + $element['#printed'] = TRUE; + } + } + + return $element; + } + +} diff --git a/modules/contrib/commerce/modules/wizard/src/Form/WizardForm.php b/modules/contrib/commerce/modules/wizard/src/Form/WizardForm.php new file mode 100644 index 0000000..b4461fa --- /dev/null +++ b/modules/contrib/commerce/modules/wizard/src/Form/WizardForm.php @@ -0,0 +1,175 @@ + 'textfield', + '#type' => 'stepper', + '#title' => $this->t('1. Store Details'), + '#button_text' => t('Next, location'), + ]; + + $form['store_details']['name'] = [ + '#type' => 'textfield', + '#title' => $this->t('Name'), + '#required' => TRUE, + ]; + + $form['store_details']['e-mail'] = [ + '#type' => 'textfield', + '#title' => $this->t('E-mail'), + '#required' => TRUE, + ]; + + $form['store_details']['owner'] = [ + '#type' => 'textfield', + '#title' => $this->t('Owner'), + ]; + + /* + * 2. Store Location + */ + $form['commerce_location'] = [ + '#type' => 'stepper', + '#title' => t('2. Enter the stores location'), + '#button_text' => t('Next, currency'), + ]; + + $form['commerce_location']['country'] = [ + '#type' => 'textfield', + '#title' => $this->t('Country'), + '#required' => TRUE, + ]; + + $form['commerce_location']['street_address'] = [ + '#type' => 'textfield', + '#title' => $this->t('Street Address'), + '#required' => TRUE, + ]; + + $form['commerce_location']['city'] = [ + '#type' => 'textfield', + '#title' => $this->t('City'), + '#required' => TRUE, + ]; + + $form['commerce_location']['province'] = [ + '#type' => 'dropdown', + '#title' => $this->t('Province'), + '#required' => TRUE, + ]; + + $form['commerce_location']['postal_code'] = [ + '#type' => 'textfield', + '#title' => $this->t('Postal Code'), + '#required' => TRUE, + ]; + + /* + * 3. Currency + */ + $form['commerce_currency'] = [ + '#type' => 'stepper', + '#title' => t('3. Confirm the stores primary currency'), + '#markup' => t('

We\'ve determined that based on your stores location, the following currency: Canadian Dollar (CAD) will be imported.

'), + '#button_text' => t('Confirm'), + '#skip_text' => t('I\'ll set it up later'), + ]; + + /* + * 4. Tax + */ + $form['commerce_tax'] = [ + '#type' => 'stepper', + '#title' => t('4. Confirm the stores primary tax rate(s)'), + '#markup' => t('

We\'ve determined that based on your stores location, the following tax rates; GST & PST will be imported.

'), + '#button_text' => t('Confirm'), + '#skip_text' => t('I\'ll set it up later'), + ]; + + /* + * 5. Cart Block + */ + $form['commerce_cart_block'] = [ + '#type' => 'stepper', + '#title' => t('5. Place your cart block in a region'), + '#markup' => t('

As a default, the cart block consists of; the number of items added to the users cart, their total, and a link to proceed to their cart for review & checkout.

+

Select a region on your site where you’d like customers to view this block.

'), + '#button_text' => t('Place block'), + '#skip_text' => t('I\'ll set it up later'), + ]; + + /* + * 6. Payment + */ + $form['commerce_payment'] = [ + '#type' => 'stepper', + '#title' => t('6. Add a payment processor'), + '#markup' => t('

Start accepting payments by choosing from 30+ supported payment processors.

'), + '#change_link' => FALSE, + ]; + + + /* + * Form Actions + */ + //$form['actions'] = ['#type' => 'actions']; + $form['actions']['submit'] = [ + '#type' => 'submit', + '#value' => t('Create Store'), + '#attributes' => [ + 'class' => ['button', 'button--primary'], + ], + '#disabled' => TRUE, + ]; + + $form['actions']['cancel'] = [ + '#type' => 'link', + '#title' => $this->t('Exit wizard'), + '#url' => Url::fromRoute('commerce.commerce_wizard'), + '#attributes' => [ + 'class' => ['button', 'button--danger'], + ], + ]; + + return $form; + } + + /** + * {@inheritdoc} + */ + public function validateForm(array &$form, FormStateInterface $form_state) { + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + } + +} diff --git a/modules/contrib/commerce/modules/wizard/templates/commerce-wizard.html.twig b/modules/contrib/commerce/modules/wizard/templates/commerce-wizard.html.twig new file mode 100644 index 0000000..25b3fea --- /dev/null +++ b/modules/contrib/commerce/modules/wizard/templates/commerce-wizard.html.twig @@ -0,0 +1,52 @@ +{# +/** + * @file + * + * Default template for the wizard form. + * + * Available variables: + * - attributes: HTML attributes for the wrapper. + * @ingroup themeable + */ +#} +
+ +

{{ intro_title }}

+

{{ intro_text }}

+ + {% trans %} +
    +
  1. + Add store details
    + Enter a name for your store, and an email to receive notifications from it. +
  2. +
  3. + Enter the stores location
    + Add the store physical address, or choose one closest to its' location. +
  4. +
  5. + Confirm the stores primary currency
    + We’ll try to determine your stores currency based on the location you've entered. +
  6. +
  7. + Confirm the stores primary tax rate(s)
    + We’ll try to determine your stores tax rate(s) based on the location you’ve entered. +
  8. +
  9. + Place your cart block in a region
    + Next, choose where your customers will see the number of items they've added to their cart on your site. +
  10. +
  11. + Add a payment processor
    + Start accepting payments by choosing from over 30 supported payment processors. +
  12. +
+ +
+ Begin Setup + No, thanks +
+ + {% endtrans %} + +
diff --git a/modules/contrib/commerce/modules/wizard/templates/stepper.html.twig b/modules/contrib/commerce/modules/wizard/templates/stepper.html.twig new file mode 100644 index 0000000..41efe9e --- /dev/null +++ b/modules/contrib/commerce/modules/wizard/templates/stepper.html.twig @@ -0,0 +1,51 @@ +{# +/** + * @file + * Theme override for a details element. + * + * Available variables + * - attributes: A list of HTML attributes for the details element. + * - errors: (optional) Any errors for this details element, may not be set. + * - title: (optional) The title of the element, may not be set. + * - description: (optional) The description of the element, may not be set. + * - children: (optional) The children of the element, may not be set. + * - value: (optional) The value of the element, may not be set. + * + * @see template_preprocess_details() + */ +#} + + {%- if title -%} +
+
{{ title }} + + ({{ 'Edit'|trans }}) +
+ +
+ {%- endif -%} + +
+ + {% if errors %} +
+ {{ errors }} +
+ {% endif %} + {%- if children -%} + {{ children }} + {%- endif -%} + {%- if value -%} + {{ value }} + {%- endif -%} + + {%- if (button_text or skip_text) -%} +
+ {%- if button_text -%}{{ button_text }}{%- endif -%} + {%- if skip_text -%}{{ skip_text }}{%- endif -%} +
+ {%- endif -%} + +
+ +