Add delegated administration to your storefront

A delegated administrator is a contact whose storefront role has been set to administrator.

Using delegated administration features in the storefront itself, a delegated administrator can perform tasks such as adding new contacts to an account, specifying roles (such as buyer or administrator) for contacts in an account, and specifying account-level billing and shipping addresses.

This section provides information about modifying your storefront to provide delegated administration features to contacts with administrator privileges.

Note: For more information on assigning delegated administration privileges to contacts, see Understand delegated administration.

Add delegated administration widgets to the Profile Layout

To add the delegated administration feature to your storefront pages, you must modify the Profile Layout. Specifically, the Profile Layout has access to two widgets that provide delegated administration features:

  • The Account Contacts widget provides the delegated administrator with an interface for viewing, adding, removing, and modifying account contacts. Using this widget, the delegated administrator can also activate a contact as well as give administrator privileges to a contact. Note that a delegated administrator cannot remove the administrator role from her own profile; however, she can remove the administrator role from another contact. Similarly, a delegated administrator cannot deactivate herself but she can deactivate other delegated administrators.
  • The Account Addresses widget allows a delegated administrator to specify account-level addresses. This widget also allows a delegated administrator to specify a default billing address and a default shipping address for the account.

To add these widgets to the Profile Layout, you must create a version of the Profile Layout for account-based shoppers only. To do this, go to the Design page, clone the Profile Layout, give it a descriptive name, enable the ‘Display layout to account shoppers only’ option, and save the clone.

To add the delegated administration widgets to the clone you created, you can create a vertical tab stack and place the widgets on individual tabs within the stack. To restrict the display of the delegated administration tabs to contacts that have administrator privileges, you can add something similar to the following code snippet in the vertical tab stack’s template (this snippet assumes you used “My Profile”, “Account Addresses”, and “Account Contacts” as the display names for the tabs that hold the Customer Profile, Account Contacts, and Account Addresses widgets, respectively):

($data.displayName() == 'My Profile') ||
((($data.displayName() == 'Account Contacts') ||
($data.displayName() == 'Account Addresses')) &&
($masterViewModel.data.global.user.roles[0].function === 'admin'))

This code snippet shows the My Profile tab to all contacts but restricts the display of the Account Contacts and Account Addresses tabs to contacts with administrator privileges.

For more information on vertical tab stacks, see Customize your store layouts and Use Stacks for Increased Widget Layout Control.

Render custom properties of contacts on the storefront

Note: The information in this section applies only to rendering custom properties of contacts when accessed on the storefront by delegated administrators. For more general information about rendering custom properties of shopper profiles, see Access custom properties using the UserViewModel.

To render custom properties of contacts on your storefront, customize the JavaScript in the Account Contacts widget to access the dynamicProperties observable array in the delegatedAdminContacts view model. For example:

define(
    //-------------------------------------------------------------------
    // DEPENDENCIES
    //-------------------------------------------------------------------
    ['jquery', 'knockout', 'ccLogger', 'ccRestClient', 'ccConstants',
    'viewModels/dynamicPropertyMetaContainer'],
    //-------------------------------------------------------------------
    // Module definition
    //-------------------------------------------------------------------
    function($, ko, CCLogger, ccRestClient, CCConstants,
      DynamicPropertyMetaContainer) {
      'use strict';
      return {
        dynamicProperties: ko.observableArray(),
        onLoad : function(widget) {
          var self = this;
          widget.listingViewModel= ko.observable();
          widget.listingViewModel(new DelegatedAdminContacts());
        },
        getDynamicPropertyMetadata: function(widget) {
         var dynamicPropertyMetaInfo = DynamicPropertyMetaContainer.getInstance();
           if (dynamicPropertyMetaInfo &&
           dynamicPropertyMetaInfo.dynamicPropertyMetaCache &&
           dynamicPropertyMetaInfo.dynamicPropertyMetaCache.
           hasOwnProperty("user")) {
             this.dynamicProperties(dynamicPropertyMetaInfo.
           dynamicPropertyMetaCache["user"]);
          }
        },
        beforeAppear: function(page) {
         var widget = this;
         if (widget.listingViewModel&&
           widget.listingViewModel().dynamicPropertyMetaInfo &&
           widget.listingViewModel().dynamicPropertyMetaInfo.
           dynamicPropertyMetaCache && widget.listingViewModel().
           dynamicPropertyMetaInfo.dynamicPropertyMetaCache.
           hasOwnProperty(CCConstants.ENDPOINT_SHOPPER_TYPE_PARAM)) {
             this.getDynamicPropertyMetadata();
         }
        },

       koToJS: function() {
         var widget = this;
         var data = {};

         for(var i =0; i < widget.dynamicProperties().length; i++) {
           data[widget.dynamicProperties()[i].id()] =
           widget.listingViewModel()[this.dynamicProperties()[i].id()]();
         }
         widget.isDelegatedAdminFormEdited = true;
         return data;
       },
    }
  }
);

Modify the widget’s template file to include Knockout bindings similar to the following:

<div id="CC-contact-dynamic-property">
  <!-- ko foreach: dynamicProperties -->
    <label data-bind="attr: {id: 'CC-label-contact-dynamicProperty-'+id()},
      text: label">
    </label>
    <input data-bind="attr: {id: 'CC-edit-contact-dynamicProperty-'+id(),
      type: uiEditorType, required: required},
      value: $parent.listingViewModel()[id()]">
    <br>
  <!--/ko-->
</div>

Notify a contact of delegated administration changes

When a delegated administrator adds or removes a contact from an account, an Account Assignment Changed notification email is sent to the contact. When a delegated administrator adds or removes a role from a contact, a Role Assignment Changed notification email is sent to the contact. For more information on these email templates and how you can modify them, see Configure Email Settings and Customize Email Templates.