{"version":3,"file":"components/testimonials-list.17e814bdd95a719ffe39.js","mappings":"gIAGA,MAmPaA,EAnPW,CAACC,EAAMC,EAAqBC,KAClD,IAAIC,EACAC,EACAC,EAKJ,MAsJMC,EAAyBC,IAC7B,MAAMC,EAAmBC,SAASC,cAAc,UAShD,OAPAF,EAAiBG,UAAYJ,EAAKK,MAClCJ,EAAiBK,iBAAiB,SAAS,KACzC,MAAMC,EAAeP,EAAKQ,IAAIC,MAAM,SAAS,GAC7CC,IACAf,EAAmBY,EAAa,IAG3BN,CAAgB,EAmCnBS,EAAqB,KACzBd,EAAwBe,UAAUC,IAAI,QACtCf,EAAec,UAAUE,OAAO,OAAO,EAazC,MA1M2B,MACzB,MAAMC,EAAUZ,SAASC,cAAc,KACvCW,EAAQH,UAAUC,IAAI,KAAM,aAAc,YAE1C,MAAMG,EAAOb,SAASC,cAAc,QACpCY,EAAKX,UAAY,iBAAiBX,OAElCI,EAAiBK,SAASC,cAAc,OACxCN,EAAec,UAAUC,IAAI,eAC7Bf,EAAemB,YAAYF,GAC3BjB,EAAemB,YAAYD,GAE3BrB,EAAoBsB,YAAYnB,EAAe,EAnB/CoB,GA0BArB,EAA0BM,SAASC,cAAc,MACjDP,EAAwBe,UAAUC,IAAI,aAAc,QACpDlB,EAAoBsB,YAAYpB,GAqL3B,CAMLsB,OAASC,IACPvB,EAAwBQ,UAAY,GAlJV,CAACe,IAlCG,CAACA,IACjC,MAAMC,EAAkBD,EAAiBE,MACtCC,KAAI,CAACtB,EAAMuB,IAA0B,QAAfvB,EAAKK,MAAkBkB,GAAS,IACtDC,QAAQD,GAAUA,GAAS,IAE9B,IAAIE,EAAQL,EAAgBM,MAAMH,GAAUA,EAAQ,IAChDI,EAAMP,EAAgBM,MAAMH,GAAUA,EAAQ,IAElD,MAAMK,EAAW,GAkBjB,OAhBIH,GACFG,EAASC,KAAK,GAGZF,GACFC,EAASC,KAAK,IAGZJ,IAAUE,GACZC,EAASC,QAAQ,CAAC,EAAG,EAAG,EAAG,GAAGC,MAAMX,EAAiBY,UAAYZ,EAAiBa,eAGhFL,IAAQF,GACVG,EAASC,QAAQ,CAAC,EAAG,EAAG,EAAG,IAAIC,MAAMX,EAAiBa,aAAe,IAGhEJ,CAAQ,EASfK,CAA0Bd,GACvBe,MAAK,CAACC,EAAGC,IAAMA,EAAID,IACnBE,SAASd,IACRJ,EAAiBE,MAAMiB,OAAOf,EAAO,EAAE,IAGpCJ,EAAiBE,MAAMC,KAAKtB,IACjCA,EAAKK,MAAQL,EAAKK,MAAMkC,QAAQ,aAAc,IAAIA,QAAQ,aAAc,IAEjEvC,MA0IPwC,CAAsBrB,GAAkBkB,SAASrC,IAC/CJ,EAAwBoB,YAzCJ,EAACG,EAAkBnB,KAC3C,OAAQA,EAAKK,OACX,IAAK,WACH,MA3FwB,EAACc,EAAkBnB,KAC/C,MAAMyC,EAAiBvC,SAASC,cAAc,MAW9C,OATAsC,EAAe9B,UAAUC,IAAI,uBAES,IAAlCO,EAAiBa,cACnBS,EAAe9B,UAAUC,IAAI,YAC7B6B,EAAerC,UAAY,SAASJ,EAAKK,gBAEzCoC,EAAezB,YAAYjB,EAAsBC,IAG5CyC,CAAc,EA+EVC,CAAsBvB,EAAkBnB,GACjD,IAAK,OACH,MAxEoB,EAACmB,EAAkBnB,KAC3C,MAAMyC,EAAiBvC,SAASC,cAAc,MAW9C,OATAsC,EAAe9B,UAAUC,IAAI,mBAEzBO,EAAiBa,eAAiBb,EAAiBY,WACrDU,EAAe9B,UAAUC,IAAI,YAC7B6B,EAAerC,UAAY,SAASJ,EAAKK,gBAEzCoC,EAAezB,YAAYjB,EAAsBC,IAG5CyC,CAAc,EA4DVE,CAAkBxB,EAAkBnB,GAC7C,IAAK,MACH,MApB8B,MAClC,MAAMyC,EAAiBvC,SAASC,cAAc,MAI9C,OAFAsC,EAAe9B,UAAUC,IAAI,YAEtB6B,CAAc,EAeVG,GACT,QACE,MAxDgB,CAAC5C,IACrB,MAAMyC,EAAiBvC,SAASC,cAAc,MAS9C,OAPIH,EAAK6C,QACPJ,EAAe9B,UAAUC,IAAI,WAC7B6B,EAAerC,UAAY,iCAAiCJ,EAAKK,gBAEjEoC,EAAezB,YAAYjB,EAAsBC,IAG5CyC,CAAc,EA8CVK,CAAc9C,GACzB,EA+BwC+C,CAAkB5B,EAAkBnB,GAAM,IAEhFF,EAAcqB,EAAiBa,aAlBjCnC,EAAec,UAAUC,IAAI,QAC7BhB,EAAwBe,UAAUE,OAAO,OAkBnB,EAKtBmC,MAAO,KACLtC,IACAd,EAAwBQ,UAAY,EAAE,EAEzC,ECiDH,IA9RO,WACL,IAAI6C,EACAC,EACAC,EACAC,EAEJ,MAAMC,EAAqB,CAAC,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,OAEnGC,EAAc,CAClB,CAAEC,GAAI,SAAUC,OAAQ,YAAaC,UAAW,QAChD,CAAEF,GAAI,SAAUC,OAAQ,YAAaC,UAAW,OAChD,CAAEF,GAAI,gBAAiBC,OAAQ,SAAUC,UAAW,QACpD,CAAEF,GAAI,eAAgBC,OAAQ,SAAUC,UAAW,QAGrD,IAAIC,EAKJ,MAiCMC,EAAiBC,IACrBX,EAAUD,QACVU,EAAqBJ,EAAYO,MAAMC,GAAWA,EAAOP,KAAOK,IAChEG,EAAQ,EAAE,EASNA,EAAU,CAACC,EAAMC,GAAc,KACnCC,EAAEC,KAAK,CACL3D,IAAK,4CAAuCkD,EAAmBF,UAAUE,EAAmBD,YAC5FW,KAAM,CAAEJ,KAAMA,GACdK,KAAM,MACNC,SAAU,OACVC,QAAUC,GAAaC,EAA2BD,EAAUP,GAC5DS,MAAOC,GACP,EASEF,EAA6B,CAACD,EAAUP,KAC5CW,EAAwBJ,EAASK,cAC7BZ,GACFa,OAAOC,SAAS,CAAEC,IAAK9B,EAAqB+B,wBAAwBC,EAAI,IAAKC,SAAU,UACzF,EAMIR,EAAkC,KACtC,MAAMS,EAAmBlF,SAASC,cAAc,MAQhD,MANAiF,EAAiBhF,UAAY,oCAC7BgF,EAAiBzE,UAAUC,IAAI,mBAE/BsC,EAAqB9C,UAAY,GACjC8C,EAAqBlC,YAAYoE,GAE3B,IAAIC,MAAM,6BAA6B,EAQzCT,EAA2BC,IAC/B3B,EAAqB9C,UAAY,GACjCkF,EAAUT,GACVA,EAAaT,KAAK/B,SAASkD,GAAgBC,EAAoBD,KAC/DtC,EAAU/B,OAAO2D,EAAa,EAQ1BS,EAAaT,IACjB1B,EAAiB/C,UACf,QAAQyE,EAAa7C,4BACN6C,EAAaY,GAAKZ,EAAaa,KAAO,QAAQb,EAAac,eAAe,EAQvFH,EAAuBD,IAC3B,MAAMK,EAAa1F,SAASC,cAAc,OAC1C0F,EAA6BD,EAAYL,GACzCrC,EAAqBlC,YAAY4E,EAAW,EA6BxCC,EAA+B,CAACD,EAAYL,EAAaO,GAAmB,KAChFP,EAAYQ,QAZ0B,CAACR,IACvC,OAVaS,GAUCT,EAAYU,cAAgBV,EAAYW,YAAcX,EAAYY,mBAAqB,EAT9FC,OAAOC,KAAKC,MAAMN,QAAXK,OADF,IAACL,CAU6F,EAWpFO,CAAgChB,GAAaiB,WAEnEZ,EAAWxF,UAAYqG,EAAiClB,GACxDmB,EAA0Cd,EAAYL,GAClDO,GACFa,EAAqCf,GAAYxF,UAAY,+BAC7DwG,EAAsBhB,IAEtBiB,EAAsCjB,EAAYL,EACpD,EAQIqB,EAAyBhB,IAC7B,CAAC,iBAAkB,sBAAsBvD,SAASyE,IAChDlB,EAAWmB,cAAc,IAAID,KAAanG,UAAUC,IAAI,WAAW,GACnE,EASEiG,EAAwC,CAACjB,EAAYL,IACzD,CACE,CAAEuB,UAAW,iBAAkBE,eAAgB,oBAC/C,CAAEF,UAAW,qBAAsBE,eAAgB,qBACnD3E,SAAQ,EAAGyE,YAAWE,oBACtBpB,EAAWmB,cAAc,IAAID,KAAaxG,iBAAiB,SAAS,KAClEiF,EAAYyB,KACZ9C,EAAEC,KAAK,CACL3D,IAAK,sCAAiC+E,EAAYhC,KAClDa,KAAM,CACJ6C,iBAAkB1B,EAAY0B,iBAC9BC,iBAAkB3B,EAAY2B,kBAEhC7C,KAAM,MACNC,SAAU,OACVC,QAAS,IAAMsB,EAA6BD,EAAYL,GAAa,GACrEb,MAAO,IAAMyC,EAA0BvB,IACvC,MASFuB,EAA6BvB,IACjC,MAAMwB,EAAoCT,EAAqCf,GAM/E,MAJAwB,EAAkChH,UAAY,oCAC9CgH,EAAkCzG,UAAUC,IAAI,mBAChDgG,EAAsBhB,GAEhB,IAAIP,MAAM,oCAAoC,EAQhDsB,EAAwCf,GACrCA,EAAWmB,cAAc,wBAS5BL,EAA4C,CAACd,EAAYL,IAC7D,CACE,CAAEuB,UAAW,yBAA0BE,eAAgB,iBACvD,CAAEF,UAAW,uBAAwBE,eAAgB,eACrD,CAAEF,UAAW,6BAA8BE,eAAgB,qBAC3D,CAAEF,UAAW,yBAA0BE,eAAgB,YACvD3E,SAAQ,EAAGyE,YAAWE,qBACtBpB,EAAWmB,cAAc,IAAID,KAAaO,MAAMC,MAAyC,GAA9B/B,EAAYyB,GAAf,GAAsC,IAQ5FP,EAAoClB,IACxCgC,OC1OyBhE,ED0OgB,uBC1OZiE,ED0OoC,CAC/DC,QAASlC,EAAYU,cACrByB,MAAOnC,EAAYW,YACnByB,YAAapC,EAAYY,kBACzBJ,QAASR,EAAYQ,QACrB6B,QAASrC,EAAYsC,QACrBC,KAAMC,EAAUxC,EAAYyC,WAC5BC,aAAc1C,EAAY0B,iBAAmB1B,EAAY2B,iBACzDgB,gBAAiB3C,EAAY0B,kBC7Pb,EAACkB,EAAKX,IACjB,IAAIY,YAAYC,OAAOC,KAAKd,GAAS,YAAYW,OAAjD,IAA8DE,OAAOE,OAAOf,IAW1EgB,CA3Ba,CAACjF,IACvB,MAAMkF,EAAWvI,SAASwI,eAAenF,GACzC,IAAKkF,EACH,MAAM,IAAIpD,MAAM,qBAAqB9B,iBAGvC,OAAOkF,EAASrI,SAAS,EAqBJuI,CAAgBpF,GAAKiE,GADlB,IAACjE,EAAIiE,CDmP3B,EAOEO,EAAaa,IACjB,MAAMd,EAAO,IAAIe,KAAKD,GAEtB,MAAO,GAAGvF,EAAmByE,EAAKgB,eAAehB,EAAKiB,cAAcjB,EAAKkB,eAAe,EAG1F9E,GAAE,KAtQAf,EAAmBjD,SAAS6G,cAAc,uBAC1C7D,EAAuBhD,SAAS6G,cAAc,2BAU9C9D,EAAYzD,EACV,eACAU,SAAS6G,cAAc,uCACtBkC,GAAelF,EAAQkF,GAAY,KAQtC7F,EAAiBlD,SAAS6G,cAAc,2BACxC3D,EAAe9C,iBAAiB,UAAW4I,GAAUvF,EAAcuF,EAAMC,OAAOnD,cAChFrC,EAAcP,EAAe4C,SA+OjC,C","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 = ` 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(/«\\s/g, '').replace(/\\s»/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":""}