javascriptpluginshandlebars.jshelperbigcommerce

How to conditionally render data within a handlebars template for a to be computed complex condition?


I use BigCommerce, and would like to only show a Return button on the order page up until 90days after an order is placed.

The Order Date format is like this: 2022 Nov 22nd

Order date is generated by {{order.date}}

The code for the Return button is: {{lang 'account.orders.details.return'}}

I have tried modifying a countdown code I use for banners, but I don't understand how to process the date format that is given by BigCommerce.

I was thinking of using a span that would show the button up until 90days from the order date.

EDIT: Sounds like this would be better handled using the template language. Any suggestions on how I can add an if statement based on 90days from todays date? Here is the original code that shows the button:

{{#if settings.returns_enabled}} {{#if order.is_complete}} {{lang 'account.orders.details.return'}} {{/if}} {{/if}}

Solution

  • The handlebar template would look like this ...

    {{#if (isWithinDateRange order.date)}}
      <a href="{{order.return_url}}" class="button">{{lang 'account.orders.details.return'}}</a>
    {{/if}}
    

    It uses a custom helper function which needs to be registered with the handlebar scripts ...

    Handlebars.registerHelper('isWithinDateRange', function (dateTime = '') {
      const rangeInDays = 90;
    
      const currentTime = Date.now();
      const orderTime = new Date(dateTime).getTime();
      const passedTimeInDays = (currentTime - orderTime) / 1000 / 60 / 60 / 24;
    
      return (passedTimeInDays < rangeInDays);
    });
    

    The data available within this template's context might be of this structure ...

    {
      order: {
        date: '2022 Nov 22',
        return_url: 'account/orders/details/return/4386834670937'
      }
    }
    

    In case one wants to fiddle with the handlebars playground, one needs to provide an additional helper which mocks the build-in handlebars lang helper function ...

    Handlebars.registerHelper('lang', function (wordingPath = 'missing.content') {
      // actually an implementation of a custom i18n API.
      return wordingPath;
    });
    

    Edit

    Since real custom handlebars helpers are not supported by BigCommerce, the OP needs to render the button and immediately after a <script/> block where the button's display state gets evaluated and accordingly updated.

    Thus the OP needs to render both the button and the script-block via template syntax where the button's display default is set to 'none' and where the correct id, date-time and time-range values get rendered as parameters into an immediately invoked function expression (IIFE).

    The time-evaluating helper-function can be applied before or within the script-block.

    2nd Edit

    As it turned out the BigCommerce API does provide dates in a non parsable form like e.g 2022 Nov 22nd ...

    I think my problem is that the order.date returned looks like this "2022 Nov 22nd". Would the "nd" at the end make it fail?

    Then one needs to sanitize such non parsable date-time strings by trimming all leading and trailing non digit characters from it. The regex is /^[^\d]+|[^\d]+$/g and does its work like that ...

    console.log(
      `"foo bar 2022 Nov 22nd".replace(/^[^\d]+|[^\d]+$/g, '') ...`,
      "foo bar 2022 Nov 22nd".replace(/^[^\d]+|[^\d]+$/g, '')
    );
    console.log(
      `new Date("2022 Nov 22nd".replace(/^[^\d]+|[^\d]+$/g, '')) ...`,
      new Date("2022 Nov 22nd".replace(/^[^\d]+|[^\d]+$/g, ''))
    );
    .as-console-wrapper { min-height: 100%!important; top: 0; }

    The final solution has been adapted according to the regex-based date-time sanitizing.

    a.button {
      display: inline-block;
      padding: 1px 3px 3px 3px;
      border: 2px outset #ccc;
      background-color: #eee;
      color: #333;
      text-decoration: none;
      text-align: center;
      cursor: pointer;
    }
    <script>
      function isWithinDateRange(dateTime = '', rangeInDays = 90) {
        const currentTime = Date.now();
        const orderTime = new Date(dateTime).getTime();
        const passedTimeInDays = (currentTime - orderTime) / 1000 / 60 / 60 / 24;
    
        return (passedTimeInDays < rangeInDays);
      };
    </script>
    
    
    <!--
    <a
      style="display:none"
      id="{{ someUniqueIdValue }}"
      href="{{ order.return_url }}"
      class="button"
    >{{ lang 'account.orders.details.return' }}</a>
    //-->
    
    
    <a
      style="display:none"
      id="someUniqueIdValue"
      href="account/orders/details/return/4386834670937"
      class="button"
    >start retour process</a>
    
    <script>
      (function (elmId, dateTime, rangeInDays) {
    
        // sanitizing a non parsable date-time string. 
        dateTime = dateTime.replace(/^[^\d]+|[^\d]+$/g, '');
    
        const displayValue
          = isWithinDateRange(dateTime, rangeInDays) && '""' || 'none';
    
        document
          .querySelector(`#${ elmId }`)
          .style.cssText = `display:${ displayValue }`;
    
      }('someUniqueIdValue', '2022 Nov 22nd', 90));
    
    //}({{ someUniqueIdValue }}, {{ order.date }}, {{ 90 }}));
    </script>