{"version":3,"file":"components/survey.bda4c6f530aac885f238.js","mappings":"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","sources":["webpack://stdcheck-exposed-wp-theme/./themes/stdcheck-exposed/src/js/services/http.js","webpack://stdcheck-exposed-wp-theme/./themes/stdcheck-exposed/src/js/services/form.js","webpack://stdcheck-exposed-wp-theme/./themes/stdcheck-exposed/src/js/components/survey.js"],"sourcesContent":["/**\n * Service class for making HTTP requests\n */\nexport function HttpService() {\n  /**\n   * Make an HTTP request that expects a JSON response\n   *\n   * @param {*} url       The URL to make the request to\n   * @param {*} options   options for the fetch function\n   *\n   * @returns {Promise}   A promise that resolves with the JSON response data, or rejects for any of these reasons:\n   *                      1. The HTTP status code is not between 200-299\n   *                      2. The response is not valid JSON\n   *                      3. Network failures or anything that prevented the HTTP request from completing\n   */\n  function fetchJson(url, options = {}) {\n    options.headers = { Accept: 'application/json', 'Content-Type': 'application/json' };\n\n    return new Promise((resolve, reject) => {\n      fetch(url, options)\n        .then((response) => {\n          if (response.ok && response.status !== 204) {\n            response.json().then((data) => resolve(data));\n          } else if (response.ok && response.status === 204) {\n            resolve();\n          } else {\n            response.json().then((errorResponse) => {\n              errorResponse.code = response.status;\n              reject(errorResponse);\n            });\n          }\n        })\n        .catch((error) => reject(error));\n    });\n  }\n\n  return {\n    /**\n     * Make a GET request to the specified URL\n     *\n     * @param {string} url  The URL to make the request to\n     *\n     * @returns {Promise} A Promise that resolves with the response data when successful, and rejects on failure\n     */\n    get: (url) => fetchJson(url, { method: 'GET' }),\n\n    /**\n     * Make a POST request to the specified URL\n     *\n     * @param {string} url  The URL to make the request to\n     * @param {any} body    The request body\n     *\n     * @returns {Promise} A Promise that resolves with the response data when successful, and rejects on failure\n     */\n    post: (url, body) => fetchJson(url, { method: 'POST', body: JSON.stringify(body) }),\n  };\n}\n","export function FormService() {\n  const errorMessageMapping = [\n    { validityState: 'valueMissing', inputMessageAttribute: 'data-required-error' },\n    { validityState: 'customError', inputMessageAttribute: 'data-custom-error' },\n    { validityState: 'patternMismatch', inputMessageAttribute: 'data-pattern-error' },\n    { validityState: 'rangeOverflow', inputMessageAttribute: 'data-max-error' },\n    { validityState: 'rangeUnderflow', inputMessageAttribute: 'data-min-error' },\n    { validityState: 'stepMismatch', inputMessageAttribute: 'data-step-error' },\n    { validityState: 'tooLong', inputMessageAttribute: 'data-maxlength-error' },\n    { validityState: 'tooShort', inputMessageAttribute: 'data-minlength-error' },\n    { validityState: 'typeMismatch', inputMessageAttribute: 'data-type-error' },\n  ];\n\n  /**\n   * Callback for the validation event listeners for a form field.\n   *\n   * @param {Event} event the event that triggered the validation\n   */\n  function validateInput(event) {\n    checkFieldValidityAndDisplayOrRemoveErrors(event.target);\n  }\n\n  /**\n   * Checks validity of a form field, and toggles the validation message accordingly.\n   *\n   * @param {Element} input the input field\n   */\n  function checkFieldValidityAndDisplayOrRemoveErrors(input) {\n    const fieldset = input.closest('fieldset');\n    const inputs = fieldset.querySelectorAll('input, textarea');\n    const errorOutput = fieldset.querySelector('output');\n    const labels = fieldset.querySelectorAll('label, legend');\n\n    if (input.checkValidity()) {\n      if (errorOutput) {\n        errorOutput.textContent = '';\n      }\n\n      inputs.forEach((input) => input.classList.remove('is-invalid-input'));\n      labels.forEach((label) => label.classList.remove('is-invalid-label'));\n\n      return;\n    }\n\n    if (errorOutput) {\n      errorOutput.textContent = getValidationMessage(input);\n    }\n\n    inputs.forEach((input) => input.classList.add('is-invalid-input'));\n    labels.forEach((label) => label.classList.add('is-invalid-label'));\n  }\n\n  /**\n   * Returns a custom or default validation message for a form field.\n   *\n   * @param {Element} input the input field\n   */\n  function getValidationMessage(input) {\n    const validationState = errorMessageMapping.find(\n      (validationStateObject) => input.validity[validationStateObject.validityState]\n    );\n\n    return input.getAttribute(validationState.inputMessageAttribute) ?? input.validationMessage;\n  }\n\n  return {\n    /**\n     * Adds validators to all of the input/textarea elements within a form.\n     *\n     * @param {string} formSelector the selector for the form\n     * @param {array}  triggerEvents the events to trigger the validation\n     */\n    setValidators: (formSelector, triggerEvents = ['input', 'blur']) => {\n      const inputs = document.querySelectorAll(`${formSelector} input, ${formSelector} textarea`);\n\n      triggerEvents.forEach((triggerEvent) => {\n        inputs.forEach((input) => {\n          input.addEventListener(triggerEvent, validateInput);\n        });\n      });\n    },\n\n    /**\n     * Runs the validation checks for all of the inputs/textareas within a form.\n     *\n     * @param {string} formSelector the selector for the form\n     */\n    validateAllInputs: (formSelector) => {\n      const inputs = document.querySelectorAll(`${formSelector} input, ${formSelector} textarea`);\n\n      inputs.forEach((input) => {\n        checkFieldValidityAndDisplayOrRemoveErrors(input);\n      });\n    },\n  };\n}\n","import { HttpService } from '../services/http';\nimport { FormService } from '../services/form';\n\nfunction SurveyComponent() {\n  const formService = new FormService();\n  const httpService = new HttpService();\n\n  function init() {\n    const params = new URLSearchParams(window.location.search);\n    if (params.has('admin')) {\n      addSurveyDate();\n    }\n\n    formService.setValidators('form#survey-form');\n  }\n\n  /**\n   * Adds survey date field and event listener so admins can copy/paste testimonials from one of our other projects.\n   */\n  function addSurveyDate() {\n    const surveyDate = document.querySelector('#surveyDate');\n    surveyDate.addEventListener('input', surveyDateValidator);\n    surveyDate.setAttribute('required', 'required');\n    surveyDate.closest('fieldset').classList.remove('hide');\n  }\n\n  /**\n   * Validates the value of the survey date field.\n   *\n   * If the value is not a valid date or string, such as \"3 days ago\", this method sets the custom validity error. If\n   * the value is valid, this method displays the parsed date in the DOM and clears the custom validity error.\n   *\n   * @param {Event} event the event\n   */\n  function surveyDateValidator(event) {\n    const date = parseSurveyDateValue(event.target);\n    const timestampHiddenField = document.querySelector('#surveyTimestamp');\n    const parsedTimestampOutput = document.querySelector('#parsedTimestampOutput');\n\n    if (!isNaN(date.getTime())) {\n      timestampHiddenField.value = date.getMonth() + 1 + '/' + date.getDate() + '/' + date.getFullYear();\n      parsedTimestampOutput.textContent = timestampHiddenField.value;\n      document.querySelector('#parsedTimestamp').classList.remove('hide');\n      document.querySelector('#surveyDate').setCustomValidity('');\n    } else {\n      timestampHiddenField.value = 'Invalid Date';\n      parsedTimestampOutput.textContent = timestampHiddenField.value;\n      document.querySelector('#parsedTimestamp').classList.remove('hide');\n      document.querySelector('#surveyDate').setCustomValidity('Invalid format for survey date');\n    }\n  }\n\n  /**\n   * Parses the surveyDate input and returns a Date object.\n   *\n   * The surveyDate field can accept the following input values:\n   *   MM/DD/YYYY\n   *   x weeks ago\n   *   x days ago\n   *   x minutes ago (simply returns the current date)\n   *   x hours ago (simply returns the current date)\n   *\n   * @param {Element} surveyDate the surveyDate field\n   */\n  function parseSurveyDateValue(surveyDate) {\n    const formattedDate = surveyDate.value.match(/(\\d+) (minute|hour|day|week)/i);\n    if (formattedDate) {\n      let date = new Date();\n      switch (formattedDate[2]) {\n        case 'week':\n          date.setDate(date.getDate() - 7 * formattedDate[1]);\n\n          return date;\n        case 'day':\n          date.setDate(date.getDate() - 1 * formattedDate[1]);\n\n          return date;\n        case 'minute':\n        case 'hour':\n        default:\n          return date;\n      }\n    } else {\n      return new Date(surveyDate.value);\n    }\n  }\n\n  /**\n   * Structures the form data for the POST request.\n   */\n  function getFormData() {\n    let body = {\n      privacy_stats: document.querySelector('[name=ratingService]:checked').value,\n      convenience_stats: document.querySelector('[name=ratingConvenience]:checked').value,\n      speed_stats: document.querySelector('[name=ratingSpeed]:checked').value,\n      comment: document.querySelector('[name=surveyDetails]').value,\n    };\n\n    const surveyTimestamp = document.querySelector('#surveyTimestamp').value;\n    if (surveyTimestamp) {\n      body.timestamp = surveyTimestamp;\n    }\n\n    return body;\n  }\n\n  /**\n   * Shows the success message once the form has been submitted.\n   */\n  function showSuccessMessage() {\n    document.querySelector('#survey-container').classList.add('hide');\n    document.querySelector('#success-container').classList.remove('hide');\n    window.scrollTo(0, 0);\n  }\n\n  /**\n   * Displays back-end error if the POST request fails.\n   *\n   * @param {Response} error the response from the back-end\n   */\n  function showBackendError(error) {\n    document.querySelector('#survey-form-error').textContent =\n      error.message ?? 'Whoops, an error occurred. Please try again later';\n    document.querySelector('#survey-form-error').classList.remove('hide');\n  }\n\n  init();\n\n  return {\n    /**\n     * Submits the survey.\n     *\n     * @param {Event} event the click event from the submit button\n     */\n    submitSurvey: function (event) {\n      event.preventDefault();\n\n      const form = document.querySelector('#survey-form');\n      if (!form.checkValidity()) {\n        formService.validateAllInputs('form#survey-form');\n        form.querySelector('#survey-form-error').classList.remove('hide');\n\n        return;\n      }\n\n      form.querySelector('#submit-survey-button').setAttribute('disabled', 'disabled');\n      form.querySelector('#survey-form-error').classList.add('hide');\n\n      httpService\n        .post(`${process.env.API_URL}/api/v1/survey`, getFormData())\n        .then(() => showSuccessMessage())\n        .catch((error) => showBackendError(error))\n        .finally(() => form.querySelector('#submit-survey-button').removeAttribute('disabled'));\n    },\n  };\n}\n\nwindow.survey = new SurveyComponent();\n"],"names":["HttpService","fetchJson","url","options","headers","Accept","Promise","resolve","reject","fetch","then","response","ok","status","json","data","errorResponse","code","catch","error","get","method","post","body","JSON","stringify","FormService","errorMessageMapping","validityState","inputMessageAttribute","validateInput","event","checkFieldValidityAndDisplayOrRemoveErrors","target","input","fieldset","closest","inputs","querySelectorAll","errorOutput","querySelector","labels","checkValidity","textContent","forEach","classList","remove","label","validationState","find","validationStateObject","validity","getAttribute","validationMessage","getValidationMessage","add","setValidators","formSelector","triggerEvents","document","triggerEvent","addEventListener","validateAllInputs","window","survey","formService","httpService","surveyDateValidator","date","surveyDate","formattedDate","value","match","Date","setDate","getDate","parseSurveyDateValue","timestampHiddenField","parsedTimestampOutput","isNaN","getTime","setCustomValidity","getMonth","getFullYear","URLSearchParams","location","search","has","setAttribute","addSurveyDate","submitSurvey","preventDefault","form","privacy_stats","convenience_stats","speed_stats","comment","surveyTimestamp","timestamp","getFormData","scrollTo","message","showBackendError","finally","removeAttribute"],"sourceRoot":""}