{"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":""}