Setting the file. One moment.
Services · Wix Headless Templates · wix/skills · Skills Docs
ContentsBack to the top of the page bookings/rest/ services.ts
TypeScript · 94 lines · 4 KB
;
11 import {
12 BOOKINGS_APP_ID,
13 CATEGORIES_QUERY,
14 LOCATIONS_QUERY,
15 OTHER_LOCATIONS_ID,
16 SERVICES_CONDITIONAL_FIELDS,
17 SERVICES_PAGE_SIZE,
18 STAFF_RESOURCE_TYPE_ID,
19 hasMorePage,
20 isKnownType,
21 servicesFilter,
22 toCategories,
23 toDetail,
24 toLocationOptions,
25 toSummary,
26 type Raw,
27 type ServicesFilterOptions,
28 } from "../app/wix/bookings/services-core.js" ;
29 import type { BookingCategory, LocationOption, ServiceDetail, ServiceSummary } from "../app/wix/bookings/types.js" ;
30
31 export { BOOKINGS_APP_ID, OTHER_LOCATIONS_ID, SERVICES_PAGE_SIZE, STAFF_RESOURCE_TYPE_ID };
32
33 export interface FetchServicesOptions extends ServicesFilterOptions {
34 limit ?: number ;
35 offset ?: number ;
36 }
37
38 export interface ServicesPage {
39 items : ServiceSummary [];
40 /** Another page follows — pass `offset + items.length`. */
41 hasMore : boolean ;
42 }
43
44 // POST /bookings/v2/services/query { query: { filter, paging: { limit, offset } }, conditionalFields }
45 async function queryServices ( filter : ServicesFilterOptions , limit : number , offset : number ) : Promise < Raw > {
46 return wixRequest < Raw >( "/bookings/v2/services/query" , {
47 body: { query: { filter: servicesFilter (filter), paging: { limit, offset } }, conditionalFields: SERVICES_CONDITIONAL_FIELDS },
48 });
49 }
50
51 /**
52 * One page of bookable services (this app's, never hidden — filtered by the server), optionally one
53 * category and/or one business location (or OTHER_LOCATIONS_ID for custom/customer locations),
54 * mapped to grid-ready DTOs. Wix pages 20 at a time; `hasMore` says whether to ask for the next.
55 */
56 export async function fetchServices ({ limit = SERVICES_PAGE_SIZE , offset = 0 , categoryId , locationId } : FetchServicesOptions = {}) : Promise < ServicesPage > {
57 const res = await queryServices ({ categoryId, locationId }, limit, offset);
58 const raws = ((res?.services ?? []) as Raw []). filter (isKnownType);
59 return { items: raws. map (( s ) => toSummary (s, imgSrc)), hasMore: hasMorePage (res?.pagingMetadata, offset, (res?.services ?? []). length , limit) };
60 }
61
62 /** One service by its URL slug (mainSlug.name) — a query with the slug in the filter. Null when not found. */
63 export async function fetchServiceBySlug ( slug : string ) : Promise < ServiceDetail | null > {
64 const raw = (( await queryServices ({ slug }, 1 , 0 ))?.services ?? [])[ 0 ] as Raw | undefined ;
65 return raw && isKnownType (raw) ? toDetail (raw, imgSrc) : null ;
66 }
67
68 /**
69 * Service categories for a filter bar — only categories that hold a bookable service, in the owner's
70 * order. Non-fatal (empty array on failure).
71 * POST /bookings/v2/services/categories/query { filter: { services: {} } }
72 */
73 export async function fetchBookingCategories () : Promise < BookingCategory []> {
74 try {
75 const res = await wixRequest < Raw >( "/bookings/v2/services/categories/query" , { body: CATEGORIES_QUERY });
76 return toCategories ((res?.categories ?? []) as Raw []);
77 } catch {
78 return [];
79 }
80 }
81
82 /**
83 * Business locations that host a visible service (a listing filter, sorted by name) plus whether any
84 * service is held at a custom/customer location (the OTHER_LOCATIONS_ID bucket). Non-fatal.
85 * POST /bookings/v2/services/locations/query { filter: { services: { appId, hidden: false } } }
86 */
87 export async function fetchLocations () : Promise <{ locations : LocationOption []; hasOtherLocations : boolean }> {
88 try {
89 const res = await wixRequest < Raw >( "/bookings/v2/services/locations/query" , { body: LOCATIONS_QUERY });
90 return toLocationOptions (res);
91 } catch {
92 return { locations: [], hasOtherLocations: false };
93 }
94 }