@tiquo/dom-package 1.5.2 → 1.6.0

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/README.md CHANGED
@@ -225,6 +225,15 @@ const confirmedBookings = await auth.getBookings({ status: 'confirmed' });
225
225
  // With pagination
226
226
  const page1 = await auth.getBookings({ limit: 10 });
227
227
  const page2 = await auth.getBookings({ limit: 10, cursor: page1.nextCursor });
228
+
229
+ // Download a QR-code ticket PDF when ticketing is enabled
230
+ const [booking] = upcomingBookings.bookings;
231
+ if (booking?.ticketing.qrCodeTicketsEnabled) {
232
+ const ticketPdf = await auth.downloadBookingTicket(booking.id);
233
+ }
234
+
235
+ // Wallet links are included when Apple Wallet / Google Wallet tickets are enabled
236
+ const walletUrl = booking?.ticketing.walletTicketUrl;
228
237
  ```
229
238
 
230
239
  **Options:**
@@ -234,10 +243,14 @@ const page2 = await auth.getBookings({ limit: 10, cursor: page1.nextCursor });
234
243
  - `upcoming` - If true, only return future bookings (sorted soonest first)
235
244
 
236
245
  **Returns:**
237
- - `bookings` - Array of booking objects with service details, date/time, and status
246
+ - `bookings` - Array of booking objects with service details, date/time, status, and `ticketing` links. `serviceName` and `serviceCategoryName` come from the booking's order-item snapshot.
238
247
  - `hasMore` - Whether there are more bookings to fetch
239
248
  - `nextCursor` - Cursor for the next page (if `hasMore` is true)
240
249
 
250
+ #### `downloadBookingTicket(bookingId): Promise<Blob>`
251
+
252
+ Download the QR-code ticket PDF for one of the authenticated customer's bookings. Use this when `booking.ticketing.qrCodeTicketsEnabled` is true. Wallet-capable bookings also expose `booking.ticketing.walletTicketUrl`, `appleWalletTicketUrl`, and `googleWalletTicketUrl`.
253
+
241
254
  #### `getEnquiries(options?): Promise<GetEnquiriesResult>`
242
255
 
243
256
  Get the authenticated customer's enquiry history. Only returns enquiries for the logged-in customer.
@@ -264,6 +277,32 @@ const page2 = await auth.getEnquiries({ limit: 10, cursor: page1.nextCursor });
264
277
  - `hasMore` - Whether there are more enquiries to fetch
265
278
  - `nextCursor` - Cursor for the next page (if `hasMore` is true)
266
279
 
280
+ #### `createEnquiry(input): Promise<CreateEnquiryResult>`
281
+
282
+ Create an enquiry from your website. `customer.email` is required. If the visitor is authenticated, the enquiry is attached to that customer. Otherwise the SDK uses your public key and allowed domain configuration, finds or creates a customer by email, and attaches the enquiry.
283
+
284
+ Submitted customer fields fill missing profile data only; existing names, phones, and customer parameter values are not overwritten.
285
+
286
+ ```typescript
287
+ const { enquiry, customer } = await auth.createEnquiry({
288
+ customer: {
289
+ email: 'customer@example.com',
290
+ firstName: 'Sam',
291
+ lastName: 'Taylor',
292
+ phone: '+44 7911 123456',
293
+ details: {
294
+ system_marketing_opt_in: true,
295
+ },
296
+ },
297
+ enquiry: {
298
+ subject: 'Private event request',
299
+ message: 'I would like to enquire about availability next Friday.',
300
+ category: 'events',
301
+ priority: 'medium',
302
+ },
303
+ });
304
+ ```
305
+
267
306
  #### `destroy(): void`
268
307
 
269
308
  Clean up resources when destroying the auth instance. Call this when your component unmounts or when you no longer need the auth instance.
package/dist/index.d.mts CHANGED
@@ -560,11 +560,22 @@ interface TiquoBooking {
560
560
  timezone: string;
561
561
  attendeeCount: number;
562
562
  /**
563
- * Service title (e.g. "OJAS Listening Room"). Empty string when the
564
- * underlying service has been deleted — render your own fallback if you
565
- * need a non-empty display string.
563
+ * Service title from the booking's order-item snapshot. Empty string when no
564
+ * order snapshot is available — render your own fallback if needed.
566
565
  */
567
566
  serviceName: string;
567
+ /**
568
+ * Service category from the booking's order-item snapshot, when captured.
569
+ */
570
+ serviceCategoryName?: string;
571
+ ticketing: {
572
+ qrCodeTicketsEnabled: boolean;
573
+ walletTicketsEnabled: boolean;
574
+ ticketDownloadUrl?: string;
575
+ walletTicketUrl?: string;
576
+ appleWalletTicketUrl?: string;
577
+ googleWalletTicketUrl?: string;
578
+ };
568
579
  serviceId: string;
569
580
  sublocationId: string;
570
581
  customerNotes?: string;
@@ -611,6 +622,40 @@ interface GetEnquiriesResult {
611
622
  hasMore: boolean;
612
623
  nextCursor?: string;
613
624
  }
625
+ interface CreateEnquiryCustomerData {
626
+ /** Required. Used to find or create the customer profile for this enquiry. */
627
+ email: string;
628
+ firstName?: string;
629
+ lastName?: string;
630
+ /**
631
+ * Primary phone number in E.164 format. The SDK auto-normalizes common
632
+ * formats before submission.
633
+ */
634
+ phone?: string;
635
+ /**
636
+ * Additional customer parameter values keyed by system parameter id
637
+ * (`system_marketing_opt_in`) or customer parameter schema id. Existing
638
+ * non-empty values are not overwritten.
639
+ */
640
+ details?: Record<string, string | number | boolean | null>;
641
+ }
642
+ interface CreateEnquiryData {
643
+ customer: CreateEnquiryCustomerData;
644
+ enquiry: {
645
+ type?: string;
646
+ subject?: string;
647
+ /** Required unless `subject` is supplied. */
648
+ message?: string;
649
+ category?: string;
650
+ priority?: "low" | "medium" | "high" | "urgent";
651
+ source?: "online" | "website" | "phone" | "email" | "walk_in" | "social" | "referral" | "pos" | "admin";
652
+ };
653
+ }
654
+ interface CreateEnquiryResult {
655
+ success: boolean;
656
+ enquiry: TiquoEnquiry;
657
+ customer: TiquoCustomer;
658
+ }
614
659
  type TiquoCompanyRelationship = "employee" | "contractor" | "manager" | "executive" | "owner" | "contact" | "other";
615
660
  /**
616
661
  * The authenticated customer's membership in a company. Each company the
@@ -772,6 +817,13 @@ declare class TiquoAuth {
772
817
  * first.
773
818
  */
774
819
  getBookings(options?: GetBookingsOptions): Promise<GetBookingsResult>;
820
+ /**
821
+ * Download a QR-code ticket PDF for one of the authenticated customer's bookings.
822
+ *
823
+ * This is only available when `booking.ticketing.qrCodeTicketsEnabled` is
824
+ * true in the booking list response.
825
+ */
826
+ downloadBookingTicket(bookingId: string): Promise<Blob>;
775
827
  /**
776
828
  * Convenience wrapper around `getBookings({ upcoming: true })` for the
777
829
  * common "show me my upcoming bookings" case. Results are sorted
@@ -805,6 +857,18 @@ declare class TiquoAuth {
805
857
  * Only returns enquiries for the logged-in customer
806
858
  */
807
859
  getEnquiries(options?: GetEnquiriesOptions): Promise<GetEnquiriesResult>;
860
+ /**
861
+ * Create a new enquiry through the DOM package.
862
+ *
863
+ * `customer.email` is required. If the current browser has an authenticated
864
+ * DOM session, the enquiry is associated with that customer. Otherwise the
865
+ * public key and allowed-domain configuration are used to accept the
866
+ * submission, find or create a customer by email, and attach the enquiry.
867
+ *
868
+ * Submitted customer details fill missing customer profile fields only; they
869
+ * do not overwrite existing profile data.
870
+ */
871
+ createEnquiry(input: CreateEnquiryData): Promise<CreateEnquiryResult>;
808
872
  /**
809
873
  * Get the companies the authenticated customer belongs to.
810
874
  *
@@ -928,6 +992,7 @@ declare function useTiquoAuth(auth: TiquoAuth): {
928
992
  getUpcomingBookings: (options?: Omit<GetBookingsOptions, "upcoming">) => Promise<GetBookingsResult>;
929
993
  getReceipt: (orderId: string) => Promise<TiquoReceipt>;
930
994
  getEnquiries: (options?: GetEnquiriesOptions) => Promise<GetEnquiriesResult>;
995
+ createEnquiry: (input: CreateEnquiryData) => Promise<CreateEnquiryResult>;
931
996
  getCompanies: () => Promise<GetCompaniesResult>;
932
997
  getCompanyColleagues: (companyId: string) => Promise<GetCompanyColleaguesResult>;
933
998
  getIframeToken: (flowId?: string) => Promise<IframeTokenResult>;
@@ -992,4 +1057,4 @@ declare class TiquoPhone {
992
1057
  static buildPhone: typeof buildPhone;
993
1058
  }
994
1059
 
995
- export { type AuthStateChangeCallback, type CountryPhoneInfo, type GetBookingsOptions, type GetBookingsResult, type GetCompaniesResult, type GetCompanyColleaguesResult, type GetEnquiriesOptions, type GetEnquiriesResult, type GetOrdersOptions, type GetOrdersResult, type IframeTokenResult, type PhoneValidationResult, type ProfilePhotoUploadResult, type ProfileUpdateData, type ProfileUpdateResult, type SendOTPResult, TiquoAnalytics, type TiquoAnalyticsConfig, type TiquoAnalyticsEventOptions, TiquoAuth, type TiquoAuthConfig, TiquoAuthError, type TiquoBooking, TiquoCMS, type TiquoCMSBlock, type TiquoCMSConfig, type TiquoCMSPage, type TiquoCMSPageRequest, type TiquoCompany, type TiquoCompanyColleague, type TiquoCompanyMembership, type TiquoCompanyRelationship, type TiquoCustomer, type TiquoCustomerEmail, type TiquoCustomerPhone, type TiquoEnquiry, type TiquoOrder, type TiquoOrderItem, TiquoPhone, type TiquoReceipt, type TiquoReceiptBusiness, type TiquoReceiptCustomer, type TiquoReceiptItem, type TiquoReceiptOrder, type TiquoSession, type TiquoUser, type VerifyOTPResult, addCustomerUserId, clearCachedEmail, TiquoAuth as default, getCustomerUserIds, getPrefilledEmailFromCookie, isDashboardSession, trackCustomerPresence, useTiquoAuth };
1060
+ export { type AuthStateChangeCallback, type CountryPhoneInfo, type CreateEnquiryCustomerData, type CreateEnquiryData, type CreateEnquiryResult, type GetBookingsOptions, type GetBookingsResult, type GetCompaniesResult, type GetCompanyColleaguesResult, type GetEnquiriesOptions, type GetEnquiriesResult, type GetOrdersOptions, type GetOrdersResult, type IframeTokenResult, type PhoneValidationResult, type ProfilePhotoUploadResult, type ProfileUpdateData, type ProfileUpdateResult, type SendOTPResult, TiquoAnalytics, type TiquoAnalyticsConfig, type TiquoAnalyticsEventOptions, TiquoAuth, type TiquoAuthConfig, TiquoAuthError, type TiquoBooking, TiquoCMS, type TiquoCMSBlock, type TiquoCMSConfig, type TiquoCMSPage, type TiquoCMSPageRequest, type TiquoCompany, type TiquoCompanyColleague, type TiquoCompanyMembership, type TiquoCompanyRelationship, type TiquoCustomer, type TiquoCustomerEmail, type TiquoCustomerPhone, type TiquoEnquiry, type TiquoOrder, type TiquoOrderItem, TiquoPhone, type TiquoReceipt, type TiquoReceiptBusiness, type TiquoReceiptCustomer, type TiquoReceiptItem, type TiquoReceiptOrder, type TiquoSession, type TiquoUser, type VerifyOTPResult, addCustomerUserId, clearCachedEmail, TiquoAuth as default, getCustomerUserIds, getPrefilledEmailFromCookie, isDashboardSession, trackCustomerPresence, useTiquoAuth };
package/dist/index.d.ts CHANGED
@@ -560,11 +560,22 @@ interface TiquoBooking {
560
560
  timezone: string;
561
561
  attendeeCount: number;
562
562
  /**
563
- * Service title (e.g. "OJAS Listening Room"). Empty string when the
564
- * underlying service has been deleted — render your own fallback if you
565
- * need a non-empty display string.
563
+ * Service title from the booking's order-item snapshot. Empty string when no
564
+ * order snapshot is available — render your own fallback if needed.
566
565
  */
567
566
  serviceName: string;
567
+ /**
568
+ * Service category from the booking's order-item snapshot, when captured.
569
+ */
570
+ serviceCategoryName?: string;
571
+ ticketing: {
572
+ qrCodeTicketsEnabled: boolean;
573
+ walletTicketsEnabled: boolean;
574
+ ticketDownloadUrl?: string;
575
+ walletTicketUrl?: string;
576
+ appleWalletTicketUrl?: string;
577
+ googleWalletTicketUrl?: string;
578
+ };
568
579
  serviceId: string;
569
580
  sublocationId: string;
570
581
  customerNotes?: string;
@@ -611,6 +622,40 @@ interface GetEnquiriesResult {
611
622
  hasMore: boolean;
612
623
  nextCursor?: string;
613
624
  }
625
+ interface CreateEnquiryCustomerData {
626
+ /** Required. Used to find or create the customer profile for this enquiry. */
627
+ email: string;
628
+ firstName?: string;
629
+ lastName?: string;
630
+ /**
631
+ * Primary phone number in E.164 format. The SDK auto-normalizes common
632
+ * formats before submission.
633
+ */
634
+ phone?: string;
635
+ /**
636
+ * Additional customer parameter values keyed by system parameter id
637
+ * (`system_marketing_opt_in`) or customer parameter schema id. Existing
638
+ * non-empty values are not overwritten.
639
+ */
640
+ details?: Record<string, string | number | boolean | null>;
641
+ }
642
+ interface CreateEnquiryData {
643
+ customer: CreateEnquiryCustomerData;
644
+ enquiry: {
645
+ type?: string;
646
+ subject?: string;
647
+ /** Required unless `subject` is supplied. */
648
+ message?: string;
649
+ category?: string;
650
+ priority?: "low" | "medium" | "high" | "urgent";
651
+ source?: "online" | "website" | "phone" | "email" | "walk_in" | "social" | "referral" | "pos" | "admin";
652
+ };
653
+ }
654
+ interface CreateEnquiryResult {
655
+ success: boolean;
656
+ enquiry: TiquoEnquiry;
657
+ customer: TiquoCustomer;
658
+ }
614
659
  type TiquoCompanyRelationship = "employee" | "contractor" | "manager" | "executive" | "owner" | "contact" | "other";
615
660
  /**
616
661
  * The authenticated customer's membership in a company. Each company the
@@ -772,6 +817,13 @@ declare class TiquoAuth {
772
817
  * first.
773
818
  */
774
819
  getBookings(options?: GetBookingsOptions): Promise<GetBookingsResult>;
820
+ /**
821
+ * Download a QR-code ticket PDF for one of the authenticated customer's bookings.
822
+ *
823
+ * This is only available when `booking.ticketing.qrCodeTicketsEnabled` is
824
+ * true in the booking list response.
825
+ */
826
+ downloadBookingTicket(bookingId: string): Promise<Blob>;
775
827
  /**
776
828
  * Convenience wrapper around `getBookings({ upcoming: true })` for the
777
829
  * common "show me my upcoming bookings" case. Results are sorted
@@ -805,6 +857,18 @@ declare class TiquoAuth {
805
857
  * Only returns enquiries for the logged-in customer
806
858
  */
807
859
  getEnquiries(options?: GetEnquiriesOptions): Promise<GetEnquiriesResult>;
860
+ /**
861
+ * Create a new enquiry through the DOM package.
862
+ *
863
+ * `customer.email` is required. If the current browser has an authenticated
864
+ * DOM session, the enquiry is associated with that customer. Otherwise the
865
+ * public key and allowed-domain configuration are used to accept the
866
+ * submission, find or create a customer by email, and attach the enquiry.
867
+ *
868
+ * Submitted customer details fill missing customer profile fields only; they
869
+ * do not overwrite existing profile data.
870
+ */
871
+ createEnquiry(input: CreateEnquiryData): Promise<CreateEnquiryResult>;
808
872
  /**
809
873
  * Get the companies the authenticated customer belongs to.
810
874
  *
@@ -928,6 +992,7 @@ declare function useTiquoAuth(auth: TiquoAuth): {
928
992
  getUpcomingBookings: (options?: Omit<GetBookingsOptions, "upcoming">) => Promise<GetBookingsResult>;
929
993
  getReceipt: (orderId: string) => Promise<TiquoReceipt>;
930
994
  getEnquiries: (options?: GetEnquiriesOptions) => Promise<GetEnquiriesResult>;
995
+ createEnquiry: (input: CreateEnquiryData) => Promise<CreateEnquiryResult>;
931
996
  getCompanies: () => Promise<GetCompaniesResult>;
932
997
  getCompanyColleagues: (companyId: string) => Promise<GetCompanyColleaguesResult>;
933
998
  getIframeToken: (flowId?: string) => Promise<IframeTokenResult>;
@@ -992,4 +1057,4 @@ declare class TiquoPhone {
992
1057
  static buildPhone: typeof buildPhone;
993
1058
  }
994
1059
 
995
- export { type AuthStateChangeCallback, type CountryPhoneInfo, type GetBookingsOptions, type GetBookingsResult, type GetCompaniesResult, type GetCompanyColleaguesResult, type GetEnquiriesOptions, type GetEnquiriesResult, type GetOrdersOptions, type GetOrdersResult, type IframeTokenResult, type PhoneValidationResult, type ProfilePhotoUploadResult, type ProfileUpdateData, type ProfileUpdateResult, type SendOTPResult, TiquoAnalytics, type TiquoAnalyticsConfig, type TiquoAnalyticsEventOptions, TiquoAuth, type TiquoAuthConfig, TiquoAuthError, type TiquoBooking, TiquoCMS, type TiquoCMSBlock, type TiquoCMSConfig, type TiquoCMSPage, type TiquoCMSPageRequest, type TiquoCompany, type TiquoCompanyColleague, type TiquoCompanyMembership, type TiquoCompanyRelationship, type TiquoCustomer, type TiquoCustomerEmail, type TiquoCustomerPhone, type TiquoEnquiry, type TiquoOrder, type TiquoOrderItem, TiquoPhone, type TiquoReceipt, type TiquoReceiptBusiness, type TiquoReceiptCustomer, type TiquoReceiptItem, type TiquoReceiptOrder, type TiquoSession, type TiquoUser, type VerifyOTPResult, addCustomerUserId, clearCachedEmail, TiquoAuth as default, getCustomerUserIds, getPrefilledEmailFromCookie, isDashboardSession, trackCustomerPresence, useTiquoAuth };
1060
+ export { type AuthStateChangeCallback, type CountryPhoneInfo, type CreateEnquiryCustomerData, type CreateEnquiryData, type CreateEnquiryResult, type GetBookingsOptions, type GetBookingsResult, type GetCompaniesResult, type GetCompanyColleaguesResult, type GetEnquiriesOptions, type GetEnquiriesResult, type GetOrdersOptions, type GetOrdersResult, type IframeTokenResult, type PhoneValidationResult, type ProfilePhotoUploadResult, type ProfileUpdateData, type ProfileUpdateResult, type SendOTPResult, TiquoAnalytics, type TiquoAnalyticsConfig, type TiquoAnalyticsEventOptions, TiquoAuth, type TiquoAuthConfig, TiquoAuthError, type TiquoBooking, TiquoCMS, type TiquoCMSBlock, type TiquoCMSConfig, type TiquoCMSPage, type TiquoCMSPageRequest, type TiquoCompany, type TiquoCompanyColleague, type TiquoCompanyMembership, type TiquoCompanyRelationship, type TiquoCustomer, type TiquoCustomerEmail, type TiquoCustomerPhone, type TiquoEnquiry, type TiquoOrder, type TiquoOrderItem, TiquoPhone, type TiquoReceipt, type TiquoReceiptBusiness, type TiquoReceiptCustomer, type TiquoReceiptItem, type TiquoReceiptOrder, type TiquoSession, type TiquoUser, type VerifyOTPResult, addCustomerUserId, clearCachedEmail, TiquoAuth as default, getCustomerUserIds, getPrefilledEmailFromCookie, isDashboardSession, trackCustomerPresence, useTiquoAuth };
package/dist/index.js CHANGED
@@ -1475,6 +1475,36 @@ var TiquoAuth = class {
1475
1475
  const result = await response.json();
1476
1476
  return result.data || { bookings: [], hasMore: false };
1477
1477
  }
1478
+ /**
1479
+ * Download a QR-code ticket PDF for one of the authenticated customer's bookings.
1480
+ *
1481
+ * This is only available when `booking.ticketing.qrCodeTicketsEnabled` is
1482
+ * true in the booking list response.
1483
+ */
1484
+ async downloadBookingTicket(bookingId) {
1485
+ await this.ensureValidToken();
1486
+ this.log("Downloading booking ticket:", bookingId);
1487
+ const url = new URL(
1488
+ `${this.config.apiEndpoint}/api/client/v1/booking-ticket`
1489
+ );
1490
+ url.searchParams.set("bookingId", bookingId);
1491
+ const response = await fetch(url.toString(), {
1492
+ method: "GET",
1493
+ headers: {
1494
+ Authorization: `Bearer ${this.accessToken}`
1495
+ },
1496
+ credentials: "include"
1497
+ });
1498
+ if (!response.ok) {
1499
+ const error = await response.json().catch(() => ({ error: "Failed to download booking ticket" }));
1500
+ throw new TiquoAuthError(
1501
+ error.error || "Failed to download booking ticket",
1502
+ "DOWNLOAD_BOOKING_TICKET_FAILED",
1503
+ response.status
1504
+ );
1505
+ }
1506
+ return response.blob();
1507
+ }
1478
1508
  /**
1479
1509
  * Convenience wrapper around `getBookings({ upcoming: true })` for the
1480
1510
  * common "show me my upcoming bookings" case. Results are sorted
@@ -1563,6 +1593,89 @@ var TiquoAuth = class {
1563
1593
  const result = await response.json();
1564
1594
  return result.data || { enquiries: [], hasMore: false };
1565
1595
  }
1596
+ /**
1597
+ * Create a new enquiry through the DOM package.
1598
+ *
1599
+ * `customer.email` is required. If the current browser has an authenticated
1600
+ * DOM session, the enquiry is associated with that customer. Otherwise the
1601
+ * public key and allowed-domain configuration are used to accept the
1602
+ * submission, find or create a customer by email, and attach the enquiry.
1603
+ *
1604
+ * Submitted customer details fill missing customer profile fields only; they
1605
+ * do not overwrite existing profile data.
1606
+ */
1607
+ async createEnquiry(input) {
1608
+ if (this.accessToken) {
1609
+ await this.refreshTokenIfNeeded();
1610
+ }
1611
+ const customer = { ...input.customer };
1612
+ if (!customer.email?.trim()) {
1613
+ throw new TiquoAuthError(
1614
+ "customer.email is required",
1615
+ "CREATE_ENQUIRY_FAILED"
1616
+ );
1617
+ }
1618
+ if (customer.phone !== void 0 && customer.phone !== "") {
1619
+ const normalized = normalizePhone(customer.phone);
1620
+ const validation = validatePhone(customer.phone);
1621
+ if (!validation.valid) {
1622
+ this.log(
1623
+ "\u26A0\uFE0F Phone validation warning:",
1624
+ validation.reason,
1625
+ "- Original:",
1626
+ customer.phone
1627
+ );
1628
+ }
1629
+ customer.phone = normalized || customer.phone;
1630
+ }
1631
+ const enquiry = { ...input.enquiry };
1632
+ if (!enquiry.message?.trim() && !enquiry.subject?.trim()) {
1633
+ throw new TiquoAuthError(
1634
+ "enquiry.message or enquiry.subject is required",
1635
+ "CREATE_ENQUIRY_FAILED"
1636
+ );
1637
+ }
1638
+ this.log("Creating customer enquiry:", {
1639
+ customer: { ...customer, email: customer.email },
1640
+ enquiry
1641
+ });
1642
+ const response = await this.request("/api/client/v1/enquiries", {
1643
+ method: "POST",
1644
+ headers: {
1645
+ "X-Public-Key": this.config.publicKey
1646
+ },
1647
+ body: JSON.stringify({
1648
+ publicKey: this.config.publicKey,
1649
+ customer,
1650
+ enquiry
1651
+ })
1652
+ });
1653
+ if (!response.ok) {
1654
+ const error = await response.json().catch(() => ({ error: "Failed to create enquiry" }));
1655
+ throw new TiquoAuthError(
1656
+ error.error || "Failed to create enquiry",
1657
+ "CREATE_ENQUIRY_FAILED",
1658
+ response.status
1659
+ );
1660
+ }
1661
+ const result = await response.json();
1662
+ const data = result.data || result;
1663
+ const createdCustomer = data.customer;
1664
+ if (this.session && createdCustomer) {
1665
+ this.session = {
1666
+ ...this.session,
1667
+ customer: createdCustomer
1668
+ };
1669
+ this.notifyListeners();
1670
+ this.broadcastTabSync("SESSION_UPDATE");
1671
+ }
1672
+ this.analytics?.identify({ identityLinkType: "enquiry" }).catch(() => void 0);
1673
+ return {
1674
+ success: true,
1675
+ enquiry: data.enquiry,
1676
+ customer: createdCustomer
1677
+ };
1678
+ }
1566
1679
  /**
1567
1680
  * Get the companies the authenticated customer belongs to.
1568
1681
  *
@@ -2277,6 +2390,7 @@ function useTiquoAuth(auth) {
2277
2390
  getUpcomingBookings: (options) => auth.getUpcomingBookings(options),
2278
2391
  getReceipt: (orderId) => auth.getReceipt(orderId),
2279
2392
  getEnquiries: (options) => auth.getEnquiries(options),
2393
+ createEnquiry: (input) => auth.createEnquiry(input),
2280
2394
  getCompanies: () => auth.getCompanies(),
2281
2395
  getCompanyColleagues: (companyId) => auth.getCompanyColleagues(companyId),
2282
2396
  getIframeToken: (flowId) => auth.getIframeToken(flowId),
package/dist/index.mjs CHANGED
@@ -1437,6 +1437,36 @@ var TiquoAuth = class {
1437
1437
  const result = await response.json();
1438
1438
  return result.data || { bookings: [], hasMore: false };
1439
1439
  }
1440
+ /**
1441
+ * Download a QR-code ticket PDF for one of the authenticated customer's bookings.
1442
+ *
1443
+ * This is only available when `booking.ticketing.qrCodeTicketsEnabled` is
1444
+ * true in the booking list response.
1445
+ */
1446
+ async downloadBookingTicket(bookingId) {
1447
+ await this.ensureValidToken();
1448
+ this.log("Downloading booking ticket:", bookingId);
1449
+ const url = new URL(
1450
+ `${this.config.apiEndpoint}/api/client/v1/booking-ticket`
1451
+ );
1452
+ url.searchParams.set("bookingId", bookingId);
1453
+ const response = await fetch(url.toString(), {
1454
+ method: "GET",
1455
+ headers: {
1456
+ Authorization: `Bearer ${this.accessToken}`
1457
+ },
1458
+ credentials: "include"
1459
+ });
1460
+ if (!response.ok) {
1461
+ const error = await response.json().catch(() => ({ error: "Failed to download booking ticket" }));
1462
+ throw new TiquoAuthError(
1463
+ error.error || "Failed to download booking ticket",
1464
+ "DOWNLOAD_BOOKING_TICKET_FAILED",
1465
+ response.status
1466
+ );
1467
+ }
1468
+ return response.blob();
1469
+ }
1440
1470
  /**
1441
1471
  * Convenience wrapper around `getBookings({ upcoming: true })` for the
1442
1472
  * common "show me my upcoming bookings" case. Results are sorted
@@ -1525,6 +1555,89 @@ var TiquoAuth = class {
1525
1555
  const result = await response.json();
1526
1556
  return result.data || { enquiries: [], hasMore: false };
1527
1557
  }
1558
+ /**
1559
+ * Create a new enquiry through the DOM package.
1560
+ *
1561
+ * `customer.email` is required. If the current browser has an authenticated
1562
+ * DOM session, the enquiry is associated with that customer. Otherwise the
1563
+ * public key and allowed-domain configuration are used to accept the
1564
+ * submission, find or create a customer by email, and attach the enquiry.
1565
+ *
1566
+ * Submitted customer details fill missing customer profile fields only; they
1567
+ * do not overwrite existing profile data.
1568
+ */
1569
+ async createEnquiry(input) {
1570
+ if (this.accessToken) {
1571
+ await this.refreshTokenIfNeeded();
1572
+ }
1573
+ const customer = { ...input.customer };
1574
+ if (!customer.email?.trim()) {
1575
+ throw new TiquoAuthError(
1576
+ "customer.email is required",
1577
+ "CREATE_ENQUIRY_FAILED"
1578
+ );
1579
+ }
1580
+ if (customer.phone !== void 0 && customer.phone !== "") {
1581
+ const normalized = normalizePhone(customer.phone);
1582
+ const validation = validatePhone(customer.phone);
1583
+ if (!validation.valid) {
1584
+ this.log(
1585
+ "\u26A0\uFE0F Phone validation warning:",
1586
+ validation.reason,
1587
+ "- Original:",
1588
+ customer.phone
1589
+ );
1590
+ }
1591
+ customer.phone = normalized || customer.phone;
1592
+ }
1593
+ const enquiry = { ...input.enquiry };
1594
+ if (!enquiry.message?.trim() && !enquiry.subject?.trim()) {
1595
+ throw new TiquoAuthError(
1596
+ "enquiry.message or enquiry.subject is required",
1597
+ "CREATE_ENQUIRY_FAILED"
1598
+ );
1599
+ }
1600
+ this.log("Creating customer enquiry:", {
1601
+ customer: { ...customer, email: customer.email },
1602
+ enquiry
1603
+ });
1604
+ const response = await this.request("/api/client/v1/enquiries", {
1605
+ method: "POST",
1606
+ headers: {
1607
+ "X-Public-Key": this.config.publicKey
1608
+ },
1609
+ body: JSON.stringify({
1610
+ publicKey: this.config.publicKey,
1611
+ customer,
1612
+ enquiry
1613
+ })
1614
+ });
1615
+ if (!response.ok) {
1616
+ const error = await response.json().catch(() => ({ error: "Failed to create enquiry" }));
1617
+ throw new TiquoAuthError(
1618
+ error.error || "Failed to create enquiry",
1619
+ "CREATE_ENQUIRY_FAILED",
1620
+ response.status
1621
+ );
1622
+ }
1623
+ const result = await response.json();
1624
+ const data = result.data || result;
1625
+ const createdCustomer = data.customer;
1626
+ if (this.session && createdCustomer) {
1627
+ this.session = {
1628
+ ...this.session,
1629
+ customer: createdCustomer
1630
+ };
1631
+ this.notifyListeners();
1632
+ this.broadcastTabSync("SESSION_UPDATE");
1633
+ }
1634
+ this.analytics?.identify({ identityLinkType: "enquiry" }).catch(() => void 0);
1635
+ return {
1636
+ success: true,
1637
+ enquiry: data.enquiry,
1638
+ customer: createdCustomer
1639
+ };
1640
+ }
1528
1641
  /**
1529
1642
  * Get the companies the authenticated customer belongs to.
1530
1643
  *
@@ -2239,6 +2352,7 @@ function useTiquoAuth(auth) {
2239
2352
  getUpcomingBookings: (options) => auth.getUpcomingBookings(options),
2240
2353
  getReceipt: (orderId) => auth.getReceipt(orderId),
2241
2354
  getEnquiries: (options) => auth.getEnquiries(options),
2355
+ createEnquiry: (input) => auth.createEnquiry(input),
2242
2356
  getCompanies: () => auth.getCompanies(),
2243
2357
  getCompanyColleagues: (companyId) => auth.getCompanyColleagues(companyId),
2244
2358
  getIframeToken: (flowId) => auth.getIframeToken(flowId),
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@tiquo/dom-package",
3
- "version": "1.5.2",
3
+ "version": "1.6.0",
4
4
  "description": "Tiquo SDK for third-party websites - authentication, customer profiles, orders, bookings, enquiries, receipts, and companies",
5
5
  "sideEffects": true,
6
6
  "publishConfig": {
7
- "access": "restricted"
7
+ "access": "public"
8
8
  },
9
9
  "main": "dist/index.js",
10
10
  "module": "dist/index.mjs",