Setting the file. One moment.
Menu · Wix Headless Templates · wix/skills · Skills Docs
ContentsBack to the top of the page Next
Bundled file Ordering
restaurants/rest/ menu.ts
TypeScript · 95 lines · 5 KB
;
11 import {
12 anyLabels,
13 assembleMenus,
14 chunk,
15 collectGroupIds,
16 collectModifierIds,
17 collectVariantIds,
18 nextCursor,
19 toSiteMoney,
20 type Raw,
21 } from "../app/wix/restaurants/menu-core.js" ;
22 import type { MenuData, SiteMoney } from "../app/wix/restaurants/types.js" ;
23
24 const get = ( path : string , query ?: Record < string , string | readonly string []>) => wixRequest < Raw >(path, { method: "GET" , query });
25
26 // The site's currency + locale are site config — read once per page, reused by every price.
27 let moneyPromise : Promise < SiteMoney > | null = null ;
28
29 /**
30 * The site's currency and locale from the eCommerce settings' BUSINESS_INFO (the read Wix's own
31 * menus code makes before formatting a price). { currency: "" } when the read fails: prices then
32 * format to "" rather than to a guessed symbol.
33 * GET /_api/ecommerce-settings/v1/ecommerce-settings?fields=BUSINESS_INFO (the path the SDK resolves on www.wixapis.com)
34 */
35 export function fetchSiteMoney () : Promise < SiteMoney > {
36 moneyPromise ??= get ( "/_api/ecommerce-settings/v1/ecommerce-settings" , { fields: [ "BUSINESS_INFO" ] })
37 . then (( res ) => toSiteMoney (res))
38 . catch (() => {
39 moneyPromise = null ; // transient failure — allow a retry on the next call
40 return { currency: "" , locale: "" };
41 });
42 return moneyPromise;
43 }
44
45 /** Every page of a cursor-paged list (?paging.cursor=…, pagingMetadata.cursors.next), the entities concatenated. */
46 async function allPages ( path : string , query : Record < string , string >, key : string ) : Promise < Raw []> {
47 const out : Raw [] = [];
48 let cursor : string | null = null ;
49 do {
50 const res : Raw = await get (path, cursor ? { ... query, "paging.cursor" : cursor } : query);
51 out. push ( ... ((res?.[key] ?? []) as Raw []));
52 cursor = nextCursor (res);
53 } while (cursor);
54 return out;
55 }
56
57 /** An id-array read in chunks of 100 ids per call (the key repeats: ?variantIds=a&variantIds=b), the entities concatenated. */
58 async function byIds ( path : string , param : string , ids : string [], key : string ) : Promise < Raw []> {
59 const pages = await Promise . all ( chunk (ids). map (( part ) => get (path, { [param]: part })));
60 return pages. flatMap (( res ) => (res?.[key] ?? []) as Raw []);
61 }
62
63 /**
64 * The site's full menu tree, assembled and display-ordered, every price formatted in the site's
65 * currency — the one entry point for every menu surface; [] when no menus exist. The three visible
66 * lists are read to the last page, then the referenced variants, modifier groups (100 ids per
67 * call), and labels, then the groups' modifiers.
68 * GET /restaurants/menus-menu/v1/menus?onlyVisible=true[&paging.cursor=…]
69 * GET /restaurants/menus-section/v1/sections?onlyVisible=true[&paging.cursor=…]
70 * GET /restaurants/menus-item/v1/items?onlyVisible=true[&paging.cursor=…]
71 * GET /restaurants/item-variants/v1/variants?variantIds=…
72 * GET /restaurants/item-modifier-group/v1/modifier-groups?modifierGroupIds=…
73 * GET /restaurants/item-modifiers/v1/modifiers?modifierIds=…
74 * GET /restaurants/item-labels/v1/labels
75 */
76 export async function fetchMenus () : Promise < MenuData []> {
77 const VISIBLE = { onlyVisible: "true" };
78 const [ menus , sections , items , money ] = await Promise . all ([
79 allPages ( "/restaurants/menus-menu/v1/menus" , VISIBLE , "menus" ),
80 allPages ( "/restaurants/menus-section/v1/sections" , VISIBLE , "sections" ),
81 allPages ( "/restaurants/menus-item/v1/items" , VISIBLE , "items" ),
82 fetchSiteMoney (),
83 ]);
84 if ( ! menus. length ) return [];
85 const variantIds = collectVariantIds (items);
86 const groupIds = collectGroupIds (items);
87 const [ variants , groups , labels ] = await Promise . all ([
88 byIds ( "/restaurants/item-variants/v1/variants" , "variantIds" , variantIds, "variants" ),
89 byIds ( "/restaurants/item-modifier-group/v1/modifier-groups" , "modifierGroupIds" , groupIds, "modifierGroups" ),
90 // List Labels has no paging: one call returns them all.
91 anyLabels (items) ? get ( "/restaurants/item-labels/v1/labels" ). then (( res ) => (res?.labels ?? []) as Raw []) : Promise . resolve ([] as Raw []),
92 ]);
93 const modifiers = await byIds ( "/restaurants/item-modifiers/v1/modifiers" , "modifierIds" , collectModifierIds (groups), "modifiers" );
94 return assembleMenus ({ menus, sections, items, variants, groups, modifiers, labels, money }, imgSrc);
95 }