@peektravel/app-utilities 0.8.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1081,6 +1081,7 @@ var errInvalidCheckbox = (v, id) => `Checkbox answer for question "${id}" must b
1081
1081
  var errUnknownOptionId = (v, id) => `No option matches id "${v}" for question "${id}"`;
1082
1082
  var errNoOptionMatch = (v, id) => `No option matches "${v}" for question "${id}"`;
1083
1083
  var errAmbiguousOption = (v, id) => `Option "${v}" matches more than one option for question "${id}"`;
1084
+ var errMissingRequired = (text, id) => `Custom question "${text}" (${id}) is required but was not answered`;
1084
1085
  function normalize(value) {
1085
1086
  return value.toLowerCase().replace(/[^a-z0-9]/g, "");
1086
1087
  }
@@ -1145,8 +1146,20 @@ function resolveOne(answer, questions) {
1145
1146
  throw new Error(errUnsupportedType(question.questionType, question.id));
1146
1147
  }
1147
1148
  }
1148
- function resolveCustomQuestionAnswers(answers, questions) {
1149
- return answers.map((answer) => resolveOne(answer, questions));
1149
+ function resolveCustomQuestionAnswers(answers, questions, options) {
1150
+ const resolved = answers.map((answer) => resolveOne(answer, questions));
1151
+ if (options?.requireRequired) {
1152
+ assertRequiredAnswered(resolved, questions);
1153
+ }
1154
+ return resolved;
1155
+ }
1156
+ function assertRequiredAnswered(resolved, questions) {
1157
+ const answered = new Set(resolved.map((answer) => answer.questionId));
1158
+ for (const question of questions) {
1159
+ if (question.isRequired && !question.perGuest && !answered.has(question.id)) {
1160
+ throw new Error(errMissingRequired(question.questionText, question.id));
1161
+ }
1162
+ }
1150
1163
  }
1151
1164
 
1152
1165
  // src/internal/peek/bookings/booking-service.ts
@@ -1663,8 +1676,9 @@ ${note}`;
1663
1676
  *
1664
1677
  * @throws {Error} when `activityId`, `availabilityTimeId`, a ticket
1665
1678
  * `resourceOptionId`/positive `quantity`, or the guest `name` is missing; when
1666
- * `markAsPaid` is set without an `idempotencyKey`; or when the quote/order
1667
- * mutations fail.
1679
+ * `markAsPaid` is set without an `idempotencyKey`; when
1680
+ * `requireRequiredQuestions` is set and a required custom question is left
1681
+ * unanswered; or when the quote/order mutations fail.
1668
1682
  */
1669
1683
  async create(input) {
1670
1684
  validateCreateInput(input);
@@ -1744,15 +1758,22 @@ ${note}`;
1744
1758
  * against; throws on the first unmatched/ambiguous/invalid answer.
1745
1759
  */
1746
1760
  async buildQuestionAnswers(input) {
1747
- const answers = input.customQuestionAnswers;
1748
- if (!answers || answers.length === 0) {
1761
+ const answers = input.customQuestionAnswers ?? [];
1762
+ const requireRequired = input.requireRequiredQuestions ?? false;
1763
+ if (answers.length === 0 && !requireRequired) {
1749
1764
  return null;
1750
1765
  }
1751
1766
  const questions = await this.deps.productService.getCustomQuestions(
1752
1767
  input.activityId
1753
1768
  );
1754
- return resolveCustomQuestionAnswers(answers, questions).map((resolved) => ({
1755
- ...resolved,
1769
+ const resolved = resolveCustomQuestionAnswers(answers, questions, {
1770
+ requireRequired
1771
+ });
1772
+ if (resolved.length === 0) {
1773
+ return null;
1774
+ }
1775
+ return resolved.map((answer) => ({
1776
+ ...answer,
1756
1777
  refid: crypto.randomUUID()
1757
1778
  }));
1758
1779
  }