Setting the file. One moment.
Events · Wix Headless Templates · wix/skills · Skills Docs
ContentsBack to the top of the page events/rest/ events.ts
TypeScript · 112 lines · 5 KB
{ imgSrc }
from
"../../shared/rest/media.js"
;
12 import {
13 DEFAULT_PAGE_SIZE,
14 DETAIL_FIELDS,
15 EVENTS_APP_ID,
16 LIST_FIELDS,
17 categoriesQuery,
18 hasMorePages,
19 listQuery,
20 rawId,
21 toCategories,
22 toDetail,
23 toSummary,
24 type ListOptions,
25 type Raw,
26 } from "../app/wix/events/events-core.js" ;
27 import type { EventCategory, EventDetail, EventSummary } from "../app/wix/events/types.js" ;
28
29 export { EVENTS_APP_ID, type ListOptions };
30
31 const notFound = ( e : unknown ) : boolean => e instanceof WixApiError && e.status === 404 ;
32
33 /** One page of a listing plus what a "load more" needs. */
34 export interface EventsPage {
35 events : EventSummary [];
36 /** Matching events overall (the page is `events`). */
37 total : number ;
38 hasMore : boolean ;
39 }
40
41 /**
42 * One page of events: UPCOMING/STARTED by default (`status: "past"` for ENDED, `"all"` for both),
43 * soonest first then newest first, optionally one category (server-side), `limit` (default 20)
44 * from `offset`. The limit is always sent: `paging.limit` defaults to 0 and a bare query answers
45 * `total: N, events: []` with no error.
46 * POST /events/v3/events/query { query: { filter: { status: { $in }, "categories.id"?: { $in } }, sort, paging: { limit, offset } }, fields }
47 * → { events, pagingMetadata: { total } }
48 */
49 export async function fetchEventsPage ( options : ListOptions = {}) : Promise < EventsPage > {
50 const { offset = 0 } = options;
51 const res = await wixRequest < Raw >( "/events/v3/events/query" , { body: { query: listQuery ({ limit: DEFAULT_PAGE_SIZE , ... options }), fields: LIST_FIELDS } });
52 const items = ((res?.events ?? []) as Raw []). map (( e ) => toSummary (e, imgSrc));
53 const total = typeof res?.pagingMetadata?.total === "number" ? res.pagingMetadata.total : offset + items. length ;
54 return { events: items, total, hasMore: hasMorePages (offset + items. length , total) };
55 }
56
57 /** The events of one page as a plain list (live events, soonest first, by default). */
58 export async function fetchEvents ( options : ListOptions = {}) : Promise < EventSummary []> {
59 return ( await fetchEventsPage (options)).events;
60 }
61
62 /**
63 * Every live date of a recurring series — the series' `recurringCategoryId` is a category every
64 * occurrence carries, so this is the listing filtered to it.
65 */
66 export async function fetchOccurrences ( recurringCategoryId : string , { limit = 100 } : { limit ?: number } = {}) : Promise < EventSummary []> {
67 if ( ! recurringCategoryId) return [];
68 return fetchEvents ({ categoryId: recurringCategoryId, limit });
69 }
70
71 /**
72 * The site's MANUAL categories (the filter pills). Runs on the visitor token: needs
73 * WIX_EVENTS.READ_CATEGORIES, which Wix's own headless demo exercises client-side but which isn't
74 * guaranteed for every site — callers catch a failure (403) and fall back to the categories on the
75 * loaded events.
76 * POST /events/v1/categories/query { query: { filter: { states: { $hasSome: ["MANUAL"] } }, paging: { limit: 100 } } } → { categories }
77 */
78 export async function fetchCategories () : Promise < EventCategory []> {
79 const res = await wixRequest < Raw >( "/events/v1/categories/query" , { body: { query: categoriesQuery () } });
80 return toCategories (res?.categories);
81 }
82
83 /**
84 * One event by URL slug; null when the slug doesn't resolve (EVENT_NOT_FOUND, 404) — a real 404,
85 * never a fallback to another event. The response is WRAPPED: { event }.
86 * GET /events/v3/events/slug/{slug}?fields=DETAILS&fields=TEXTS&fields=REGISTRATION&fields=URLS&fields=CATEGORIES&fields=FORM
87 */
88 export async function fetchEventBySlug ( slug : string ) : Promise < EventDetail | null > {
89 try {
90 const res = await wixRequest < Raw >( `/events/v3/events/slug/${ encodeURIComponent ( slug ) }` , { method: "GET" , query: { fields: DETAIL_FIELDS } });
91 return res?.event ? toDetail (res.event, imgSrc) : null ;
92 } catch (e) {
93 if ( notFound (e)) return null ;
94 throw e;
95 }
96 }
97
98 /**
99 * One event by id — the post-checkout confirmation read (the thank-you URL carries
100 * `?orderNumber=&eventId=`). On REST this response is WRAPPED too: { event } (the SDK's getEvent
101 * is the unwrapped one). GET /events/v3/events/{eventId}?fields=…
102 */
103 export async function fetchEventById ( eventId : string ) : Promise < EventDetail | null > {
104 try {
105 const res = await wixRequest < Raw >( `/events/v3/events/${ encodeURIComponent ( eventId ) }` , { method: "GET" , query: { fields: DETAIL_FIELDS } });
106 const raw : Raw | undefined = res?.event;
107 return raw && rawId (raw) ? toDetail (raw, imgSrc) : null ;
108 } catch (e) {
109 if ( notFound (e)) return null ;
110 throw e;
111 }
112 }