{"version":3,"file":"product-faqs-accordion-section.min.js","mappings":"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","sources":["webpack://lange/./sections/product-faqs-accordion/question-drawer.ts","webpack://lange/webpack/bootstrap","webpack://lange/../node_modules/uuid/dist/rng.js","webpack://lange/../node_modules/uuid/dist/stringify.js","webpack://lange/../node_modules/uuid/dist/v4.js","webpack://lange/../node_modules/@integrabeauty/assert/src/index.ts","webpack://lange/./lib/decorate-error.ts","webpack://lange/./sections/product-faqs-accordion/yotpo-create-question.ts","webpack://lange/./sections/product-faqs-accordion/question-form.ts"],"sourcesContent":["type ModalOpenedEvent = GlobalEventHandlersEventMap['modal-opened'];\ntype ModalClosedEvent = GlobalEventHandlersEventMap['modal-closed'];\n\n/**\n * Opens the ask a question drawer.\n */\nfunction onAskQuestionClicked(event: MouseEvent) {\n  const button = event.currentTarget;\n  if (!(button instanceof HTMLButtonElement)) {\n    return;\n  }\n\n  button.setAttribute('aria-expanded', 'true');\n\n  // Claim focus return before opening. Without this the modal manager has nothing of ours on its\n  // focus stack, so closing the drawer reaches down to whichever opener an earlier modal left\n  // there, and focusing that one scrolls the page away to wherever it sits.\n  const focusEvent = new Event('focus-stack-push-requested', {\n    bubbles: true,\n    composed: true\n  });\n  button.dispatchEvent(focusEvent);\n\n  // The modal manager leaves the FAQ section active while the drawer is open, so the button would\n  // stay reachable by Tab behind it. We inert it here rather than when the drawer reports it has\n  // opened, so it is out of reach right away.\n  button.inert = true;\n\n  const container = button.closest('.product-faqs');\n  const modal = container.querySelector('modal-element');\n  modal.dataset.open = 'true';\n}\n\n/**\n * The modal manager inerts every section but the one holding the open modal, so while the ask a\n * question drawer is open, the FAQ heading and the accordion stay reachable by Tab behind it. We\n * inert them ourselves. The header is left alone since the drawer sits inside it.\n */\nfunction onModalOpened(event: ModalOpenedEvent) {\n  const target = event.currentTarget;\n  if (target instanceof HTMLElement) {\n    const selector = 'header > div, accordion-element';\n    const parts = target.querySelectorAll<HTMLElement>(selector);\n    for (const part of parts) {\n      part.inert = true;\n    }\n  }\n}\n\n/**\n * Takes the section's parts back out of inert, the ask a question button included. The modal\n * manager puts focus back on that button only after this runs, and a focus call into an inert\n * element does nothing.\n */\nfunction onModalClosed(event: ModalClosedEvent) {\n  const target = event.currentTarget;\n  if (target instanceof HTMLElement) {\n    const selector = 'header > div, .ask-question, accordion-element';\n    const parts = target.querySelectorAll<HTMLElement>(selector);\n    for (const part of parts) {\n      part.inert = false;\n    }\n\n    const askQuestion = target.querySelector('.ask-question');\n    askQuestion.setAttribute('aria-expanded', 'false');\n  }\n}\n\n// Each FAQ section on the page carries its own copy of this script, and every copy runs, so we skip\n// the sections an earlier copy already set up.\nconst selector = '.product-faqs:not([data-drawer-initialized])';\nconst sections = document.querySelectorAll<HTMLElement>(selector);\nfor (const section of sections) {\n  const askQuestion = section.querySelector<HTMLElement>('.ask-question');\n  askQuestion.addEventListener('click', onAskQuestionClicked);\n\n  section.addEventListener('modal-opened', onModalOpened);\n  section.addEventListener('modal-closed', onModalClosed);\n  section.dataset.drawerInitialized = 'true';\n}\n","// The module cache\nlet __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tlet cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tlet module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","const rnds8 = new Uint8Array(16);\nexport default function rng() {\n    return crypto.getRandomValues(rnds8);\n}\n","import validate from './validate.js';\nconst byteToHex = [];\nfor (let i = 0; i < 256; ++i) {\n    byteToHex.push((i + 0x100).toString(16).slice(1));\n}\nexport function unsafeStringify(arr, offset = 0) {\n    return (byteToHex[arr[offset + 0]] +\n        byteToHex[arr[offset + 1]] +\n        byteToHex[arr[offset + 2]] +\n        byteToHex[arr[offset + 3]] +\n        '-' +\n        byteToHex[arr[offset + 4]] +\n        byteToHex[arr[offset + 5]] +\n        '-' +\n        byteToHex[arr[offset + 6]] +\n        byteToHex[arr[offset + 7]] +\n        '-' +\n        byteToHex[arr[offset + 8]] +\n        byteToHex[arr[offset + 9]] +\n        '-' +\n        byteToHex[arr[offset + 10]] +\n        byteToHex[arr[offset + 11]] +\n        byteToHex[arr[offset + 12]] +\n        byteToHex[arr[offset + 13]] +\n        byteToHex[arr[offset + 14]] +\n        byteToHex[arr[offset + 15]]).toLowerCase();\n}\nfunction stringify(arr, offset = 0) {\n    const uuid = unsafeStringify(arr, offset);\n    if (!validate(uuid)) {\n        throw TypeError('Stringified UUID is invalid');\n    }\n    return uuid;\n}\nexport default stringify;\n","import rng from './rng.js';\nimport { unsafeStringify } from './stringify.js';\nfunction v4(options, buf, offset) {\n    if (!buf && !options && crypto.randomUUID) {\n        return crypto.randomUUID();\n    }\n    return _v4(options, buf, offset);\n}\nfunction _v4(options, buf, offset) {\n    options = options || {};\n    const rnds = options.random ?? options.rng?.() ?? rng();\n    if (rnds.length < 16) {\n        throw new Error('Random bytes length must be >= 16');\n    }\n    rnds[6] = (rnds[6] & 0x0f) | 0x40;\n    rnds[8] = (rnds[8] & 0x3f) | 0x80;\n    if (buf) {\n        offset = offset || 0;\n        if (offset < 0 || offset + 16 > buf.length) {\n            throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);\n        }\n        for (let i = 0; i < 16; ++i) {\n            buf[offset + i] = rnds[i];\n        }\n        return buf;\n    }\n    return unsafeStringify(rnds);\n}\nexport default v4;\n","/**\n * Throws an assertion error if the given condition is falsy.\n *\n * @param expression any expression, although one that evaluates to true or false is preferred by\n * convention\n * @param message optional error text\n */\nexport function assert(expression: unknown, message?: string) {\n  if (!expression) {\n    throw new AssertionError(message);\n  }\n}\n\nexport class AssertionError extends Error {\n  constructor(message = 'Assertion error') {\n    super(message);\n    this.name = this.constructor.name;\n  }\n}\n","/**\n * Copies a single piece of supplementary context onto an error before it is thrown or reported.\n *\n * Use this when decorating a value the calling code did not construct, such as a caught value or an\n * error handed in by another module. An error the caller just built with new is always writable, so\n * plain assignment is fine there. A value from elsewhere may be a foreign object this code does not\n * own. Such a value can carry a non-writable property, such as a DOMException whose code is a read-\n * only accessor, or be frozen outright, and assigning to it then throws. Attaching context must\n * never itself fail, so a rejected assignment is swallowed and the remaining context is still\n * attempted. Guarding each property in isolation means a single read-only slot, the common case,\n * costs only that one property rather than all of them.\n *\n * In practice the value that triggers this is almost always a DOMException that reached the caller\n * from a fetch the browser cut short, such as an abort when an in-flight request is interrupted.\n * The platform defines a DOMException's code, name, and message as read-only attributes, so\n * assigning a code onto one throws under the strict mode that all bundled module code runs in. It\n * surfaces from Safari far more than elsewhere for two reasons. The reported wording, attempted to\n * assign to readonly property, is JavaScriptCore's phrasing for this failure, so the same bug in\n * another engine is worded differently and groups as a separate report, which makes this one look\n * Safari specific even though the read-only rule is not. And iOS Safari abandons in-flight fetches\n * aggressively when a tab is backgrounded or a connection drops, which is when such a DOMException\n * tends to be produced and handed to code that assumed an ordinary writable error.\n *\n * A swallowed failure is logged at a level low enough that it is recorded as a breadcrumb for\n * monitoring rather than escalated into its own captured event. That keeps the lost context visible\n * alongside the eventual report without adding fresh noise of its own. The breadcrumb names the\n * property that could not be attached, the kind of value that rejected it, and why, which is enough\n * to recognize a read-only or frozen caught value after the fact.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Read-only\n * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMException\n * @see https://webidl.spec.whatwg.org/#dfn-read-only\n */\nexport function decorateError(error: any, key: string, value: unknown) {\n  try {\n    error[key] = value;\n  } catch (assignmentError) {\n    let reason: string;\n    if (assignmentError instanceof Error) {\n      reason = assignmentError.message;\n    } else {\n      reason = `${assignmentError}`;\n    }\n\n    console.log('Failed to assign error property', {\n      key,\n      name: error?.name,\n      tag: Object.prototype.toString.call(error),\n      reason\n    });\n  }\n}\n","import { assert } from '@integrabeauty/assert';\nimport { decorateError } from '../../lib/decorate-error.js';\n\nexport interface Input {\n  appkey: string;\n\n  /**\n   * The customer's name\n   */\n  display_name: string;\n\n  /**\n   * The customer's email\n   */\n  email: string;\n\n  /**\n   * Prevents sending of two identical questions. It is recommended to set this to true.\n   */\n  prevent_duplicate_review?: boolean;\n\n  /**\n   * The description of the product\n   */\n  product_description?: string;\n\n  /**\n   * The URL of the image of the product\n   */\n  product_image_url?: string;\n\n  /**\n   * The tag you apply to a product in Custom Questions. This can only be a single string. Products\n   * can accept one tag per product and may not contain commas.\n   */\n  product_tags?: string;\n\n  /**\n   * The name of the product\n   */\n  product_title: string;\n\n  /**\n   * The URL of the product\n   */\n  product_url: string;\n\n  /**\n   * The question the customer asks\n   */\n  review_content: string;\n\n  /**\n   * The id of the product to which the new question should be attached. This may be a SKU.\n   */\n  sku: string;\n}\n\n/**\n * Create and send a Question which requires email confirmation.\n *\n * * The sku parameter only supports alphanumeric (a...z, A...Z, 0...9), \"_\" and \"-\" characters.\n * * Products can accept one tag per product and may not contain commas (,)\n * * Adding more than one product tag per product will result in a failed request (400 Error). As a\n *   result, no new question will be created.\n *\n * It is possible to allow questions without using a confirmation email. This function only supports\n * the \"with confirmation email\" requirement.\n *\n * @see https://apidocs.yotpo.com/reference/send-question-confirmation-mail\n */\nexport async function createQuestion(input: Partial<Input>) {\n  assert(input.appkey, 'Invalid app key');\n\n  const url = new URL('/questions/send_confirmation_mail', 'https://api.yotpo.com');\n\n  let response;\n  try {\n    response = await fetch(url, {\n      headers: {\n        'Content-Type': 'application/json'\n      },\n      body: JSON.stringify(input),\n      method: 'POST',\n      mode: 'cors'\n    });\n  } catch (error) {\n    decorateError(error, 'url', url.href);\n    throw error;\n  }\n\n  if (!response.ok) {\n    const error: any = new Error('Received non-200 status code creating question');\n    error.code = response.status;\n    error.url = response.url;\n    throw error;\n  }\n\n  // We are not using response.json() because it obscures errors.\n\n  let responseText;\n  try {\n    responseText = await response.text();\n  } catch (error) {\n    decorateError(error, 'code', response.status);\n    decorateError(error, 'url', response.url);\n    throw error;\n  }\n\n  // We are not hard-casting the object to its type here. Instead, we are leaving the type as\n  // unknown initially, and then later proving the type using a type assertion.\n\n  let body;\n  try {\n    body = JSON.parse(responseText);\n  } catch (error) {\n    decorateError(error, 'body', responseText);\n    decorateError(error, 'code', response.status);\n    decorateError(error, 'url', response.url);\n    throw error;\n  }\n\n  if (!isResponseBody(body)) {\n    const error: any = new Error('Malformed response body creating question');\n    error.body = body;\n    error.code = response.status;\n    error.url = response.url;\n    throw error;\n  }\n\n  if (body.status.code > 399) {\n    const error: any = new Error('Nested response status code is not ok when creating question');\n    error.body = body;\n    error.code = response.status;\n    error.url = response.url;\n    throw error;\n  }\n\n  return body;\n}\n\nexport interface ResponseBody {\n  status: {\n    code: number;\n    message: string;\n  };\n}\n\nexport function isResponseBody(value: any): value is ResponseBody {\n  return typeof value === 'object' && value !== null && typeof value.status === 'object' &&\n    value.status !== null;\n}\n","import { v4 as uuidv4 } from 'uuid';\nimport { createQuestion, type Input } from './yotpo-create-question.js';\n\n/**\n * Takes away the errors from an earlier attempt, so someone who closed the drawer partway and comes\n * back later doesn't reopen it to a form full of red. What they typed stays, and the errors come\n * back on the next post if it's still not right.\n */\nfunction onModalOpened(event: GlobalEventHandlersEventMap['modal-opened']) {\n  if (!(event.currentTarget instanceof HTMLElement)) {\n    return;\n  }\n\n  const form = event.currentTarget.querySelector('form');\n  form.classList.remove('error');\n\n  const errorElements = form.querySelectorAll('.error');\n  for (const element of errorElements) {\n    element.classList.remove('error');\n  }\n\n  const summaries = form.querySelectorAll<HTMLElement>('.error-summary, .post-error');\n  for (const summary of summaries) {\n    summary.hidden = true;\n  }\n}\n\n/**\n * Checks the ask a question form, and posts the question when every field is filled in right.\n */\nfunction onSubmitClicked(event: MouseEvent) {\n  event.preventDefault();\n\n  const submitButton = event.currentTarget;\n  if (!(submitButton instanceof HTMLButtonElement)) {\n    return;\n  }\n\n  const form = submitButton.form;\n  const errorSummary = form.querySelector<HTMLElement>('.error-summary');\n\n  if (!form.checkValidity()) {\n    for (const element of form.elements) {\n      if (!(element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement)) {\n        continue;\n      }\n\n      if (element.checkValidity()) {\n        element.parentElement.classList.remove('error');\n      } else {\n        element.parentElement.classList.add('error');\n      }\n    }\n\n    const invalidField = form.querySelector<HTMLElement>(':invalid');\n    invalidField.focus({ focusVisible: true });\n\n    errorSummary.hidden = false;\n    return;\n  }\n\n  errorSummary.hidden = true;\n\n  postQuestion(form, submitButton).catch(console.error);\n}\n\n/**\n * Sends the question to Yotpo. Once it is accepted, we close the drawer and let the rest of the\n * page know a question was asked and who asked it.\n */\nasync function postQuestion(form: HTMLFormElement, submitButton: HTMLButtonElement) {\n  const formData = new FormData(form);\n  const displayName = formData.get('display_name');\n  const email = formData.get('email');\n  const reviewContent = formData.get('review_content');\n\n  const input: Partial<Input> = {\n    appkey: form.dataset.yotpoAppKey,\n    display_name: isString(displayName) ? displayName : '',\n    email: isString(email) ? email : '',\n    product_title: form.dataset.productTitle,\n    product_url: form.dataset.productUrl,\n    review_content: isString(reviewContent) ? reviewContent : '',\n    sku: form.dataset.productId\n  };\n\n  const loader = form.querySelector('loading-indicator');\n  submitButton.disabled = true;\n  loader.hidden = false;\n\n  try {\n    await createQuestion(input);\n  } catch (error) {\n    submitButton.disabled = false;\n    loader.hidden = true;\n    form.classList.add('error');\n\n    const postError = form.querySelector<HTMLElement>('.post-error');\n    postError.hidden = false;\n\n    console.error(error, input);\n    return;\n  }\n\n  submitButton.disabled = false;\n  loader.hidden = true;\n  form.reset();\n\n  const modal = form.closest('modal-element');\n  delete modal.dataset.open;\n\n  type Detail = WindowEventMap['yotpo-question-created']['detail'];\n  const createdEvent = new CustomEvent<Detail>('yotpo-question-created', {\n    bubbles: true,\n    composed: true,\n    detail: {\n      body: input.review_content,\n      customer_id: parseInt(form.dataset.customerId, 10),\n      email: input.email,\n      event_id: uuidv4(),\n      name: input.display_name,\n      product_title: form.dataset.productTitle,\n      product_url: form.dataset.productUrl\n    }\n  });\n  form.dispatchEvent(createdEvent);\n\n  const detail: WindowEventMap['identity-captured']['detail'] = {\n    email: input.email\n  };\n\n  // The display_name field may contain a full name. Attempt to parse it into first and last name by\n  // splitting on space. If there is only one part, treat it as the first name. If there are two\n  // parts, treat the first as the first name and the second as the last name. If there are more\n  // than two parts, treat the last part as the last name and the rest as the first name.\n  const parts = input.display_name.split(' ');\n  if (parts.length === 1) {\n    detail.first_name = parts[0];\n  } else if (parts.length === 2) {\n    detail.first_name = parts[0];\n    detail.last_name = parts[1];\n  } else {\n    detail.last_name = parts.pop();\n    detail.first_name = parts.join(' ');\n  }\n\n  const identityEvent = new CustomEvent<typeof detail>('identity-captured', {\n    bubbles: true,\n    composed: true,\n    detail\n  });\n  form.dispatchEvent(identityEvent);\n}\n\nfunction isString(value: any): value is string {\n  return typeof value === 'string';\n}\n\n// Each FAQ section on the page carries its own copy of this script, and every copy runs, so we skip\n// the sections an earlier copy already set up.\nconst sections = document.querySelectorAll<HTMLElement>(\n  '.product-faqs:not([data-form-initialized])');\nfor (const section of sections) {\n  const modal = section.querySelector('modal-element');\n  modal.addEventListener('modal-opened', onModalOpened);\n\n  const submitButton = section.querySelector<HTMLElement>('form button[type=\"submit\"]');\n  submitButton.addEventListener('click', onSubmitClicked);\n\n  section.dataset.formInitialized = 'true';\n}\n"],"names":["onAskQuestionClicked","event","button","currentTarget","HTMLButtonElement","setAttribute","focusEvent","Event","bubbles","composed","dispatchEvent","inert","closest","querySelector","dataset","open","onModalOpened","target","HTMLElement","selector","parts","querySelectorAll","part","onModalClosed","sections","document","section","addEventListener","drawerInitialized","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","undefined","exports","module","__webpack_modules__","rnds8","Uint8Array","byteToHex","i","push","toString","slice","unsafeStringify","arr","offset","toLowerCase","dist_v4","options","buf","crypto","randomUUID","_ref","_options$random","rnds","random","rng","getRandomValues","length","Error","RangeError","_v4","AssertionError","constructor","message","super","this","name","decorateError","error","key","value","assignmentError","reason","console","log","tag","Object","prototype","call","async","createQuestion","input","expression","assert","appkey","url","URL","response","responseText","body","fetch","headers","JSON","stringify","method","mode","href","ok","code","status","text","parse","form","classList","remove","errorElements","element","summaries","summary","hidden","onSubmitClicked","preventDefault","submitButton","errorSummary","checkValidity","elements","HTMLInputElement","HTMLTextAreaElement","parentElement","add","focus","focusVisible","formData","FormData","displayName","get","email","reviewContent","yotpoAppKey","display_name","isString","product_title","productTitle","product_url","productUrl","review_content","sku","productId","loader","disabled","reset","modal","createdEvent","CustomEvent","detail","customer_id","parseInt","customerId","event_id","split","first_name","last_name","pop","join","identityEvent","postQuestion","catch","formInitialized"],"sourceRoot":""}