{"version":3,"file":"components/testimonials-list.17e814bdd95a719ffe39.js","mappings":"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","sources":["webpack://stdcheck-exposed-wp-theme/./themes/stdcheck-exposed/src/js/factories/paginator-factory.js","webpack://stdcheck-exposed-wp-theme/./themes/stdcheck-exposed/src/js/components/testimonials-list.js","webpack://stdcheck-exposed-wp-theme/./themes/stdcheck-exposed/src/js/services/template-service.js"],"sourcesContent":["/**\n * Creates a paginator factory\n */\nconst createPaginator = (name, paginationContainer, changePageCallback) => {\n  let paginationListContainer;\n  let loadingSpinner;\n  let currentPage;\n\n  /**\n   * Initializes a paginator\n   */\n  const init = () => {\n    initLoadingSpinner();\n    initPaginationListContainer();\n  };\n\n  /**\n   * Initializes the loading spinner\n   */\n  const initLoadingSpinner = () => {\n    const spinner = document.createElement('i');\n    spinner.classList.add('fa', 'fa-spinner', 'fa-pulse');\n\n    const text = document.createElement('span');\n    text.innerHTML = `&nbsp;Loading ${name}...`;\n\n    loadingSpinner = document.createElement('div');\n    loadingSpinner.classList.add('text-center');\n    loadingSpinner.appendChild(spinner);\n    loadingSpinner.appendChild(text);\n\n    paginationContainer.appendChild(loadingSpinner);\n  };\n\n  /**\n   * Initializes the pagination list container\n   */\n  const initPaginationListContainer = () => {\n    paginationListContainer = document.createElement('ul');\n    paginationListContainer.classList.add('pagination', 'hide');\n    paginationContainer.appendChild(paginationListContainer);\n  };\n\n  /**\n   * Returns an array of indexes to exclude from the pagination links\n   *\n   * @param {object} paginationObject The pagination object\n   */\n  const getPaginationLinkExcludes = (paginationObject) => {\n    const ellipsesIndexes = paginationObject.links\n      .map((link, index) => (link.label === '...' ? index : -1))\n      .filter((index) => index >= 0);\n\n    let begin = ellipsesIndexes.some((index) => index < 7);\n    let end = ellipsesIndexes.some((index) => index > 7);\n\n    const excludes = [];\n\n    if (begin) {\n      excludes.push(2);\n    }\n\n    if (end) {\n      excludes.push(12);\n    }\n\n    if (begin && !end) {\n      excludes.push(...[7, 6, 5, 4].slice(paginationObject.last_page - paginationObject.current_page));\n    }\n\n    if (end && !begin) {\n      excludes.push(...[7, 8, 9, 10].slice(paginationObject.current_page - 1));\n    }\n\n    return excludes;\n  };\n\n  /**\n   * Filters the pagination links\n   *\n   * @param {object} paginationObject The pagination object\n   */\n  const filterPaginationLinks = (paginationObject) => {\n    getPaginationLinkExcludes(paginationObject)\n      .sort((a, b) => b - a)\n      .forEach((index) => {\n        paginationObject.links.splice(index, 1);\n      });\n\n    return paginationObject.links.map((link) => {\n      link.label = link.label.replace(/&laquo;\\s/g, '').replace(/\\s&raquo;/g, '');\n\n      return link;\n    });\n  };\n\n  /**\n   * Builds the previous page link\n   *\n   * @param {object} paginationObject The pagination object\n   * @param {object} link             The link object\n   */\n  const buildPreviousPageLink = (paginationObject, link) => {\n    const paginationItem = document.createElement('li');\n\n    paginationItem.classList.add('pagination-previous');\n\n    if (paginationObject.current_page === 1) {\n      paginationItem.classList.add('disabled');\n      paginationItem.innerHTML = `<span>${link.label}</span>`;\n    } else {\n      paginationItem.appendChild(buildPaginationButton(link));\n    }\n\n    return paginationItem;\n  };\n\n  /**\n   * Builds the next page link\n   *\n   * @param {object} paginationObject The pagination object\n   * @param {object} link             The link object\n   */\n  const buildNextPageLink = (paginationObject, link) => {\n    const paginationItem = document.createElement('li');\n\n    paginationItem.classList.add('pagination-next');\n\n    if (paginationObject.current_page === paginationObject.last_page) {\n      paginationItem.classList.add('disabled');\n      paginationItem.innerHTML = `<span>${link.label}</span>`;\n    } else {\n      paginationItem.appendChild(buildPaginationButton(link));\n    }\n\n    return paginationItem;\n  };\n\n  /**\n   * Builds a page link\n   *\n   * @param {object} link The link object\n   */\n  const buildPageLink = (link) => {\n    const paginationItem = document.createElement('li');\n\n    if (link.active) {\n      paginationItem.classList.add('current');\n      paginationItem.innerHTML = `<span class=\"has-white-color\">${link.label}</span>`;\n    } else {\n      paginationItem.appendChild(buildPaginationButton(link));\n    }\n\n    return paginationItem;\n  };\n\n  /**\n   * Builds a pagination button\n   *\n   * @param {object} link The link object\n   */\n  const buildPaginationButton = (link) => {\n    const paginationButton = document.createElement('button');\n\n    paginationButton.innerHTML = link.label;\n    paginationButton.addEventListener('click', () => {\n      const selectedPage = link.url.split('page=')[1];\n      showLoadingSpinner();\n      changePageCallback(selectedPage);\n    });\n\n    return paginationButton;\n  };\n\n  /**\n   * Builds a pagination ellipsis item\n   */\n  const buildPaginationEllipsisItem = () => {\n    const paginationItem = document.createElement('li');\n\n    paginationItem.classList.add('ellipsis');\n\n    return paginationItem;\n  };\n\n  /**\n   * Returns the pagination item\n   *\n   * @param {object} paginationObject The pagination object\n   */\n  const getPaginationItem = (paginationObject, link) => {\n    switch (link.label) {\n      case 'Previous':\n        return buildPreviousPageLink(paginationObject, link);\n      case 'Next':\n        return buildNextPageLink(paginationObject, link);\n      case '...':\n        return buildPaginationEllipsisItem();\n      default:\n        return buildPageLink(link);\n    }\n  };\n\n  /**\n   * Shows the loading spinner\n   */\n  const showLoadingSpinner = () => {\n    paginationListContainer.classList.add('hide');\n    loadingSpinner.classList.remove('hide');\n  };\n\n  /**\n   * Hides the loading spinner\n   */\n  const hideLoadingSpinner = () => {\n    loadingSpinner.classList.add('hide');\n    paginationListContainer.classList.remove('hide');\n  };\n\n  init();\n\n  return {\n    /**\n     * Updates the pagination container\n     *\n     * @param {object} paginationObject The pagination object\n     */\n    update: (paginationObject) => {\n      paginationListContainer.innerHTML = '';\n\n      filterPaginationLinks(paginationObject).forEach((link) => {\n        paginationListContainer.appendChild(getPaginationItem(paginationObject, link));\n      });\n      currentPage = paginationObject.current_page;\n      hideLoadingSpinner();\n    },\n    /**\n     * Clears the pagination container\n     */\n    clear: () => {\n      showLoadingSpinner();\n      paginationListContainer.innerHTML = '';\n    },\n  };\n};\n\nexport const paginatorFactory = { create: createPaginator };\n","import { paginatorFactory } from '../factories/paginator-factory';\nimport { templateService } from '../services/template-service';\n\n/**\n * Testimonials list component\n */\nexport function TestimonialsListComponent() {\n  let paginator;\n  let ratingItemsContainer;\n  let ratingListHeader;\n  let sortBySelector;\n\n  const monthAbbreviations = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];\n\n  const sortOptions = [\n    { id: 'newest', sortBy: 'timestamp', direction: 'desc' },\n    { id: 'oldest', sortBy: 'timestamp', direction: 'asc' },\n    { id: 'highest-rated', sortBy: 'rating', direction: 'desc' },\n    { id: 'lowest-rated', sortBy: 'rating', direction: 'asc' },\n  ];\n\n  let selectedSortOption;\n\n  /**\n   * Initializes the testimonials list.\n   */\n  const init = () => {\n    ratingListHeader = document.querySelector('#rating-list-header');\n    ratingItemsContainer = document.querySelector('#rating-items-container');\n\n    initPaginator();\n    initSortBySelector();\n  };\n\n  /**\n   * Initializes the paginator.\n   */\n  const initPaginator = () => {\n    paginator = paginatorFactory.create(\n      'Testimonials',\n      document.querySelector('#rating-items-pagination-container'),\n      (pageNumber) => getPage(pageNumber, true)\n    );\n  };\n\n  /**\n   * Initializes the sort by selector.\n   */\n  const initSortBySelector = () => {\n    sortBySelector = document.querySelector('#testimonials-sort-menu');\n    sortBySelector.addEventListener('change', (event) => setSortOption(event.target.value));\n    setSortOption(sortBySelector.value);\n  };\n\n  /**\n   * Sets the sort option\n   *\n   * @param {string} optionId The id of the sort option\n   */\n  const setSortOption = (optionId) => {\n    paginator.clear();\n    selectedSortOption = sortOptions.find((option) => option.id === optionId);\n    getPage(1);\n  };\n\n  /**\n   * Gets the page of testimonials\n   *\n   * @param {number}  page        The page number\n   * @param {boolean} returnToTop Whether or not to scroll to the top of the testimonials list\n   */\n  const getPage = (page, returnToTop = false) => {\n    $.ajax({\n      url: `${process.env.API_URL}/testimonials/${selectedSortOption.sortBy}/${selectedSortOption.direction}`,\n      data: { page: page },\n      type: 'GET',\n      dataType: 'json',\n      success: (response) => handleTestimonialsResponse(response, returnToTop),\n      error: handleTestimonialsResponseError,\n    });\n  };\n\n  /**\n   * Handles the testimonials response\n   *\n   * @param {object}  response    The response object\n   * @param {boolean} returnToTop Whether or not to scroll to the top of the testimonials list\n   */\n  const handleTestimonialsResponse = (response, returnToTop) => {\n    setPageFromTestimonials(response.testimonials);\n    if (returnToTop) {\n      window.scrollBy({ top: ratingItemsContainer.getBoundingClientRect().y - 270, behavior: 'smooth' });\n    }\n  };\n\n  /**\n   * Handles the testimonials response error\n   */\n  const handleTestimonialsResponseError = () => {\n    const errorTextElement = document.createElement('h2');\n\n    errorTextElement.innerHTML = 'Error: Failed to get testimonials';\n    errorTextElement.classList.add('has-alert-color');\n\n    ratingItemsContainer.innerHTML = '';\n    ratingItemsContainer.appendChild(errorTextElement);\n\n    throw new Error('Failed to get testimonials');\n  };\n\n  /**\n   * Sets the list of testimonials based on the response\n   *\n   * @param {object} testimonials The testimonials pagination object\n   */\n  const setPageFromTestimonials = (testimonials) => {\n    ratingItemsContainer.innerHTML = '';\n    setHeader(testimonials);\n    testimonials.data.forEach((testimonial) => appendNewRatingItem(testimonial));\n    paginator.update(testimonials);\n  };\n\n  /**\n   * Sets the header of the testimonials list\n   *\n   * @param {object} testimonials The testimonials pagination object\n   */\n  const setHeader = (testimonials) => {\n    ratingListHeader.innerHTML =\n      `Page ${testimonials.current_page}:` +\n      ` Displaying ${testimonials.to - testimonials.from + 1} of ${testimonials.total} Reviews`;\n  };\n\n  /**\n   * Appends a new rating item to the testimonials list\n   *\n   * @param {object} testimonial The testimonial object\n   */\n  const appendNewRatingItem = (testimonial) => {\n    const ratingItem = document.createElement('div');\n    setRatingItemFromTestimonial(ratingItem, testimonial);\n    ratingItemsContainer.appendChild(ratingItem);\n  };\n\n  /**\n   * Rounds a number to the specified number of decimals\n   *\n   * @param {number} value    The value to round\n   * @param {number} decimals The number of decimals to round to\n   */\n  const round = (value, decimals) => {\n    return Number(Math.round(value + 'e' + decimals) + 'e-' + decimals);\n  };\n\n  /**\n   * Calculates the overall rating from the testimonial\n   *\n   * @param {object} testimonial The testimonial object\n   */\n  const calculateOverallFromTestimonial = (testimonial) => {\n    return round((testimonial.privacy_stats + testimonial.speed_stats + testimonial.convenience_stats) / 3, 1);\n  };\n\n  /**\n   * Sets the rating item from the testimonial\n   *\n   * @param {HTMLDivElement} ratingItem       The rating item element\n   * @param {object}         testimonial      The testimonial object\n   * @param {boolean}        feedbackReceived Whether or not feedback was already received for this testimonial\n   */\n  const setRatingItemFromTestimonial = (ratingItem, testimonial, feedbackReceived = false) => {\n    testimonial.overall = calculateOverallFromTestimonial(testimonial).toString();\n\n    ratingItem.innerHTML = getRatingItemHtmlFromTestimonial(testimonial);\n    setRatingItemProgressBarsFromTestimonials(ratingItem, testimonial);\n    if (feedbackReceived) {\n      getHelpfulReviewTextContainerElement(ratingItem).innerHTML = 'Thank you for your feedback!';\n      disableHelpfulButtons(ratingItem);\n    } else {\n      setHelpfulButtonCallbacksOnRatingItem(ratingItem, testimonial);\n    }\n  };\n\n  /**\n   * Disables the helpful buttons on the rating item\n   *\n   * @param {HTMLDivElement} ratingItem The rating item element\n   */\n  const disableHelpfulButtons = (ratingItem) => {\n    ['helpful-button', 'not-helpful-button'].forEach((className) => {\n      ratingItem.querySelector(`.${className}`).classList.add('disabled');\n    });\n  };\n\n  /**\n   * Sets the helpful button callbacks on the rating item\n   *\n   * @param {HTMLDivElement} ratingItem  The rating item element\n   * @param {object}         testimonial The testimonial object\n   */\n  const setHelpfulButtonCallbacksOnRatingItem = (ratingItem, testimonial) =>\n    [\n      { className: 'helpful-button', testimonialKey: 'positive_ratings' },\n      { className: 'not-helpful-button', testimonialKey: 'negative_ratings' },\n    ].forEach(({ className, testimonialKey }) =>\n      ratingItem.querySelector(`.${className}`).addEventListener('click', () => {\n        testimonial[testimonialKey]++;\n        $.ajax({\n          url: `${process.env.API_URL}/survey/${testimonial.id}`,\n          data: {\n            positive_ratings: testimonial.positive_ratings,\n            negative_ratings: testimonial.negative_ratings,\n          },\n          type: 'PUT',\n          dataType: 'json',\n          success: () => setRatingItemFromTestimonial(ratingItem, testimonial, true),\n          error: () => handleRatingResponseError(ratingItem),\n        });\n      })\n    );\n\n  /**\n   * Handles the rating response error\n   *\n   * @param {HTMLDivElement} ratingItem The rating item element\n   */\n  const handleRatingResponseError = (ratingItem) => {\n    const helpfulReviewTextContainerElement = getHelpfulReviewTextContainerElement(ratingItem);\n\n    helpfulReviewTextContainerElement.innerHTML = 'Error: Failed to submit feedback.';\n    helpfulReviewTextContainerElement.classList.add('has-alert-color');\n    disableHelpfulButtons(ratingItem);\n\n    throw new Error('Error: Failed to submit feedback.');\n  };\n\n  /**\n   * Gets the helpful review text container element\n   *\n   * @param {HTMLDivElement} ratingItem The rating item element\n   */\n  const getHelpfulReviewTextContainerElement = (ratingItem) => {\n    return ratingItem.querySelector('.helpful-review-text');\n  };\n\n  /**\n   * Sets the rating item progress bars from the testimonial\n   *\n   * @param {HTMLDivElement} ratingItem  The rating item element\n   * @param {object}         testimonial The testimonial object\n   */\n  const setRatingItemProgressBarsFromTestimonials = (ratingItem, testimonial) =>\n    [\n      { className: 'service-progress-meter', testimonialKey: 'privacy_stats' },\n      { className: 'speed-progress-meter', testimonialKey: 'speed_stats' },\n      { className: 'convenience-progress-meter', testimonialKey: 'convenience_stats' },\n      { className: 'overall-progress-meter', testimonialKey: 'overall' },\n    ].forEach(({ className, testimonialKey }) => {\n      ratingItem.querySelector(`.${className}`).style.width = `${testimonial[testimonialKey] * 10}%`;\n    });\n\n  /**\n   * Gets the rating item html from the testimonial\n   *\n   * @param {object} testimonial The testimonial object\n   */\n  const getRatingItemHtmlFromTestimonial = (testimonial) =>\n    templateService().renderHtmlFromTemplate('rating-item-template', {\n      service: testimonial.privacy_stats,\n      speed: testimonial.speed_stats,\n      convenience: testimonial.convenience_stats,\n      overall: testimonial.overall,\n      content: testimonial.comment,\n      date: parseDate(testimonial.timestamp),\n      totalRatings: testimonial.positive_ratings + testimonial.negative_ratings,\n      positiveRatings: testimonial.positive_ratings,\n    });\n\n  /**\n   * Parses the date from the 8601 timestamp\n   *\n   * @param {string} _8601TimeStamp The 8601 timestamp\n   */\n  const parseDate = (_8601TimeStamp) => {\n    const date = new Date(_8601TimeStamp);\n\n    return `${monthAbbreviations[date.getMonth()]} ${date.getDate()}, ${date.getFullYear()}`;\n  };\n\n  $(() => init());\n}\n\nnew TestimonialsListComponent();\n","/**\n * Service to render HTML from templates.\n */\nexport function templateService() {\n  /**\n   * Gets the template HTML from the DOM.\n   */\n  const getTemplateHtml = (id) => {\n    const template = document.getElementById(id);\n    if (!template) {\n      throw new Error(`Template with id \"${id}\" not found.`);\n    }\n\n    return template.innerHTML;\n  };\n\n  /**\n   * Interpolates a string with the given params.\n   *\n   * @param {string} str    The string to interpolate\n   * @param {object} params The params to interpolate with\n   */\n  const interpolate = (str, params) => {\n    return new Function(...Object.keys(params), `return \\`${str}\\`;`)(...Object.values(params));\n  };\n\n  return {\n    /**\n     * Renders HTML from a template.\n     *\n     * @param {string} id     The id of the template in the DOM\n     * @param {object} params The params to send to the template\n     */\n    renderHtmlFromTemplate: (id, params) => {\n      return interpolate(getTemplateHtml(id), params);\n    },\n  };\n}\n"],"names":["paginatorFactory","name","paginationContainer","changePageCallback","paginationListContainer","loadingSpinner","currentPage","buildPaginationButton","link","paginationButton","document","createElement","innerHTML","label","addEventListener","selectedPage","url","split","showLoadingSpinner","classList","add","remove","spinner","text","appendChild","initLoadingSpinner","update","paginationObject","ellipsesIndexes","links","map","index","filter","begin","some","end","excludes","push","slice","last_page","current_page","getPaginationLinkExcludes","sort","a","b","forEach","splice","replace","filterPaginationLinks","paginationItem","buildPreviousPageLink","buildNextPageLink","buildPaginationEllipsisItem","active","buildPageLink","getPaginationItem","clear","paginator","ratingItemsContainer","ratingListHeader","sortBySelector","monthAbbreviations","sortOptions","id","sortBy","direction","selectedSortOption","setSortOption","optionId","find","option","getPage","page","returnToTop","$","ajax","data","type","dataType","success","response","handleTestimonialsResponse","error","handleTestimonialsResponseError","setPageFromTestimonials","testimonials","window","scrollBy","top","getBoundingClientRect","y","behavior","errorTextElement","Error","setHeader","testimonial","appendNewRatingItem","to","from","total","ratingItem","setRatingItemFromTestimonial","feedbackReceived","overall","value","privacy_stats","speed_stats","convenience_stats","Number","Math","round","calculateOverallFromTestimonial","toString","getRatingItemHtmlFromTestimonial","setRatingItemProgressBarsFromTestimonials","getHelpfulReviewTextContainerElement","disableHelpfulButtons","setHelpfulButtonCallbacksOnRatingItem","className","querySelector","testimonialKey","positive_ratings","negative_ratings","handleRatingResponseError","helpfulReviewTextContainerElement","style","width","templateService","params","service","speed","convenience","content","comment","date","parseDate","timestamp","totalRatings","positiveRatings","str","Function","Object","keys","values","interpolate","template","getElementById","getTemplateHtml","_8601TimeStamp","Date","getMonth","getDate","getFullYear","pageNumber","event","target"],"sourceRoot":""}