@estoreclub/api 0.0.0-stage → 0.1.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/dist/bridgeClient.d.ts +10 -0
- package/dist/bridgeClient.js +10 -0
- package/dist/bridgeClient.js.map +7 -0
- package/dist/chunks/chunk-2554RPSS.js +45 -0
- package/dist/chunks/chunk-2554RPSS.js.map +7 -0
- package/dist/chunks/chunk-2BH4QPV2.js +27 -0
- package/dist/chunks/chunk-2BH4QPV2.js.map +7 -0
- package/dist/chunks/chunk-3KEEGSMP.js +86 -0
- package/dist/chunks/chunk-3KEEGSMP.js.map +7 -0
- package/dist/chunks/chunk-5DN7L6LX.js +861 -0
- package/dist/chunks/chunk-5DN7L6LX.js.map +7 -0
- package/dist/chunks/chunk-DUVULZ6N.js +111 -0
- package/dist/chunks/chunk-DUVULZ6N.js.map +7 -0
- package/dist/chunks/chunk-GJZ7EZEF.js +25 -0
- package/dist/chunks/chunk-GJZ7EZEF.js.map +7 -0
- package/dist/chunks/chunk-HFEQWXG6.js +24 -0
- package/dist/chunks/chunk-HFEQWXG6.js.map +7 -0
- package/dist/chunks/chunk-OFFTL6RC.js +24 -0
- package/dist/chunks/chunk-OFFTL6RC.js.map +7 -0
- package/dist/chunks/chunk-TSERNR4R.js +15 -0
- package/dist/chunks/chunk-TSERNR4R.js.map +7 -0
- package/dist/chunks/chunk-ZITPZDI7.js +280 -0
- package/dist/chunks/chunk-ZITPZDI7.js.map +7 -0
- package/dist/client.d.ts +407 -0
- package/dist/client.js +14 -0
- package/dist/client.js.map +7 -0
- package/dist/companyApiKey.d.ts +9 -0
- package/dist/companyApiKey.js +9 -0
- package/dist/companyApiKey.js.map +7 -0
- package/dist/customerToken.d.ts +18 -0
- package/dist/customerToken.js +11 -0
- package/dist/customerToken.js.map +7 -0
- package/dist/errors.d.ts +41 -0
- package/dist/errors.js +9 -0
- package/dist/errors.js.map +7 -0
- package/dist/index.d.ts +82 -0
- package/dist/index.js +166 -0
- package/dist/index.js.map +7 -0
- package/dist/language.d.ts +27 -0
- package/dist/language.js +11 -0
- package/dist/language.js.map +7 -0
- package/dist/params.d.ts +58 -0
- package/dist/params.js +27 -0
- package/dist/params.js.map +7 -0
- package/dist/requestCache.d.ts +46 -0
- package/dist/requestCache.js +9 -0
- package/dist/requestCache.js.map +7 -0
- package/dist/siteData.d.ts +237 -0
- package/dist/siteData.js +132 -0
- package/dist/siteData.js.map +7 -0
- package/dist/types.d.ts +2123 -0
- package/dist/types.js +1 -0
- package/dist/types.js.map +7 -0
- package/dist/visitorCountry.d.ts +25 -0
- package/dist/visitorCountry.js +15 -0
- package/dist/visitorCountry.js.map +7 -0
- package/package.json +64 -4
- package/README.md +0 -3
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,2123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the public API answers with.
|
|
3
|
+
*
|
|
4
|
+
* These mirror the server's DTOs (`companyResponse.dto.ts`,
|
|
5
|
+
* `productCategoryWithTranslations.dto.ts`, `productWithTranslations.dto.ts`) and stop at the
|
|
6
|
+
* fields a site actually renders. Optional means the API marks it optional — a product with
|
|
7
|
+
* no price or no photo is ordinary, and the caller has to handle it.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Which dataset version a record belongs to, as the API reports it (`PublicCart.workspace`).
|
|
11
|
+
*
|
|
12
|
+
* The public API serves only `production`, what visitors see, so no client asks for one: there
|
|
13
|
+
* is no workspace parameter to send.
|
|
14
|
+
*/
|
|
15
|
+
export type Workspace = "production" | "sandbox";
|
|
16
|
+
export interface PublicLanguage {
|
|
17
|
+
code: string;
|
|
18
|
+
codeLocal: string;
|
|
19
|
+
name: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The shop's terms and privacy policy, for a customer asked to accept them (`getTerms`).
|
|
23
|
+
*/
|
|
24
|
+
export interface PublicTerms {
|
|
25
|
+
/**
|
|
26
|
+
* Whether customers must accept them (the shop's Terms & privacy rule). While true, a
|
|
27
|
+
* signed-in customer who has not accepted cannot order or book (`customer_terms_required`)
|
|
28
|
+
* until they do - `updateCustomerProfile({ acceptTerms: true })`.
|
|
29
|
+
*/
|
|
30
|
+
required: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* The text the shop wrote, Markdown, in the visitor's language - else the shop's default
|
|
33
|
+
* language's. Null: none written; link `termsUrl` / `privacyUrl` instead. Render it as
|
|
34
|
+
* Markdown WITHOUT raw HTML.
|
|
35
|
+
*/
|
|
36
|
+
markdown: string | null;
|
|
37
|
+
/** The language `markdown` is in; null with it. */
|
|
38
|
+
language: string | null;
|
|
39
|
+
/** When the text last changed (ISO); null with it. */
|
|
40
|
+
updatedAt: string | null;
|
|
41
|
+
/** The shop's terms address; empty: the site's own `/terms` page, or `markdown` in place. */
|
|
42
|
+
termsUrl: string;
|
|
43
|
+
/** The shop's privacy policy address; empty: the site's `/privacy`, or `markdown` in place. */
|
|
44
|
+
privacyUrl: string;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* One of the shop's physical locations — a restaurant, a pickup point — for a "find us" section
|
|
48
|
+
* or a map. The address is the one Google verified when the shop entered it, so `latitude` /
|
|
49
|
+
* `longitude` and `placeId` always describe the same place as `address`.
|
|
50
|
+
*/
|
|
51
|
+
export interface PublicStoreLocation {
|
|
52
|
+
id: string;
|
|
53
|
+
/**
|
|
54
|
+
* The shop's own number for the location (`2`). Use it in your site's addresses
|
|
55
|
+
* (`/book?location=2`) - every `locationId` the API takes accepts it as well as `id`.
|
|
56
|
+
*/
|
|
57
|
+
number: number;
|
|
58
|
+
name: string;
|
|
59
|
+
/** Free text the shop wrote: how to find the entrance, parking. Empty when none. */
|
|
60
|
+
description: string;
|
|
61
|
+
/** ISO 3166-1 alpha-2, e.g. `"NZ"`. Null on a location saved before countries were asked. */
|
|
62
|
+
countryCode: string | null;
|
|
63
|
+
/** The city, as Google names it — e.g. `"Auckland"`. */
|
|
64
|
+
city: string | null;
|
|
65
|
+
cityPlaceId: string | null;
|
|
66
|
+
/** Postcode, e.g. `"1011"`. Null when none was given. */
|
|
67
|
+
postalCode: string | null;
|
|
68
|
+
/** As the shop writes it, e.g. `"+64 9 123 4567"` — for a `tel:` link, strip the spaces. */
|
|
69
|
+
phone: string | null;
|
|
70
|
+
/** The location's own contact address — for a `mailto:` link. */
|
|
71
|
+
email: string | null;
|
|
72
|
+
/**
|
|
73
|
+
* When it is open, sorted by day: ISO weekday (1 = Monday … 7 = Sunday) and `HH:MM` times on
|
|
74
|
+
* the shop's clock; an `until` not after `from` runs past midnight. A weekday with no range is
|
|
75
|
+
* CLOSED. `null` means the shop gave no hours — print nothing rather than "closed".
|
|
76
|
+
*/
|
|
77
|
+
workingHours: Array<{
|
|
78
|
+
day: number;
|
|
79
|
+
from: string;
|
|
80
|
+
until: string;
|
|
81
|
+
}> | null;
|
|
82
|
+
/**
|
|
83
|
+
* The street part only — "120 Ponsonby Road, Grey Lynn". The city and country are `city` and
|
|
84
|
+
* `countryCode`; print them after it for a full line.
|
|
85
|
+
*/
|
|
86
|
+
address: string;
|
|
87
|
+
/** Google Place ID — for a "directions" link: `https://www.google.com/maps/place/?q=place_id:<placeId>`. */
|
|
88
|
+
placeId: string;
|
|
89
|
+
latitude: number;
|
|
90
|
+
longitude: number;
|
|
91
|
+
/** Its pictures, in the shop's order — the first is the one to show in a list. */
|
|
92
|
+
images: Array<{
|
|
93
|
+
mediaId: string;
|
|
94
|
+
url: string;
|
|
95
|
+
isExternal: boolean;
|
|
96
|
+
}>;
|
|
97
|
+
/**
|
|
98
|
+
* The days ahead (90) on which other hours hold than `workingHours` — Christmas closed, a late
|
|
99
|
+
* New Year's Eve — the location's own over the shop's, by date. `kind: "hours"` replaces that
|
|
100
|
+
* day's opening hours, `"delivery"` its delivery hours; `hours` empty is CLOSED. Orders,
|
|
101
|
+
* pickup, delivery and bookings already follow them: these are for the page to SHOW ("Closed
|
|
102
|
+
* on 25 December"), and for "open now" on such a day, read them before `workingHours`.
|
|
103
|
+
*/
|
|
104
|
+
specialDays: Array<{
|
|
105
|
+
date: string;
|
|
106
|
+
kind: "hours" | "delivery";
|
|
107
|
+
hours: Array<{
|
|
108
|
+
from: string;
|
|
109
|
+
until: string;
|
|
110
|
+
}>;
|
|
111
|
+
note: string;
|
|
112
|
+
}>;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* What the platform knows of a picture the site holds only as a URL — see `lookupImages`. The
|
|
116
|
+
* fields `Image` from `@estoreclub/client` draws a `srcset` from.
|
|
117
|
+
*/
|
|
118
|
+
export interface PublicImage {
|
|
119
|
+
url: string;
|
|
120
|
+
width: number | null;
|
|
121
|
+
height: number | null;
|
|
122
|
+
/** Widths (px) of the resized WebP copies stored beside it, as `<name>@<width>.webp`. */
|
|
123
|
+
variants: number[];
|
|
124
|
+
}
|
|
125
|
+
export interface PublicMedia {
|
|
126
|
+
id: string;
|
|
127
|
+
url: string;
|
|
128
|
+
type: string;
|
|
129
|
+
description?: string;
|
|
130
|
+
/** The original's size in pixels. Set once the resized copies are made; absent until then. */
|
|
131
|
+
width?: number | null;
|
|
132
|
+
height?: number | null;
|
|
133
|
+
/**
|
|
134
|
+
* Widths (px) of the resized WebP copies stored beside the original as
|
|
135
|
+
* `<name>@<width>.webp`. Empty until they are made, and always for external or SVG media —
|
|
136
|
+
* render it with `Image` from `@estoreclub/client`, which falls back to `url`.
|
|
137
|
+
*/
|
|
138
|
+
variants?: number[] | null;
|
|
139
|
+
}
|
|
140
|
+
/** A company, as `GET public/company` returns it. The API never includes its key. */
|
|
141
|
+
/** Which side of the amount a currency's symbol sits on. */
|
|
142
|
+
export type CurrencySymbolPosition = "prefix" | "suffix";
|
|
143
|
+
export interface PublicCompany {
|
|
144
|
+
name: string;
|
|
145
|
+
defaultLanguage: string;
|
|
146
|
+
/** ISO 4217 code every product of this company is priced in. */
|
|
147
|
+
defaultCurrency?: string;
|
|
148
|
+
/** ISO 3166-1 alpha-2 country the shop trades in, null until it is set. */
|
|
149
|
+
countryCode?: string | null;
|
|
150
|
+
/** "₽", "$", or the code itself where a currency has no distinct sign. */
|
|
151
|
+
currencySymbol?: string;
|
|
152
|
+
/** Where that symbol goes. See `PublicSiteInfo.currencySymbolPosition`. */
|
|
153
|
+
currencySymbolPosition?: CurrencySymbolPosition;
|
|
154
|
+
/** Sales tax rate in percent; 0 for none. */
|
|
155
|
+
taxRate?: number;
|
|
156
|
+
/** Whether product prices already include the tax. */
|
|
157
|
+
taxInclusive?: boolean;
|
|
158
|
+
/** What the tax is called where the shop trades — GST, VAT, Sales tax. */
|
|
159
|
+
taxName?: string;
|
|
160
|
+
/** Whether an order names its location: never asked, the customer's choice, or a must. */
|
|
161
|
+
orderLocation?: OrderLocationMode;
|
|
162
|
+
/** How customers may receive an order, in the order offered. */
|
|
163
|
+
orderTypes?: OrderType[];
|
|
164
|
+
/** How bookings run: `off` (none), a whole table, seats at a shared table, or a time only. */
|
|
165
|
+
reservationMode?: "off" | "table" | "seat" | "time";
|
|
166
|
+
/** What a guest may book, the main way first - see `SiteInfo.reservationKinds`. */
|
|
167
|
+
reservationKinds?: ReservationKind[];
|
|
168
|
+
/** The ways visitors may sign in - signing in is always offered. */
|
|
169
|
+
customerSignInMethods?: {
|
|
170
|
+
email: boolean;
|
|
171
|
+
google: boolean;
|
|
172
|
+
apple?: boolean;
|
|
173
|
+
};
|
|
174
|
+
/** Who sees the site: everybody, or signed-in customers only. */
|
|
175
|
+
customerAccess?: CustomerAccess;
|
|
176
|
+
/** Only a signed-in customer may book a table online. */
|
|
177
|
+
reservationRequiresSignIn?: boolean;
|
|
178
|
+
/** What a reservation may be booked for - see `PublicSiteInfo.reservationOrder`. */
|
|
179
|
+
reservationOrder?: "off" | "any" | "list";
|
|
180
|
+
/** How a booking may be paid when it is made - see `PublicSiteInfo.reservationPayment`. */
|
|
181
|
+
reservationPayment?: PublicReservationPayment;
|
|
182
|
+
/** Only a signed-in customer may order online. */
|
|
183
|
+
orderRequiresSignIn?: boolean;
|
|
184
|
+
/** A guest may track a delivered order by its tracking number and email. */
|
|
185
|
+
publicOrderTracking?: boolean;
|
|
186
|
+
/** Money off for paying one way — see `PublicSiteInfo`. */
|
|
187
|
+
paymentDiscounts?: PublicPaymentDiscounts;
|
|
188
|
+
/** The Google client id for the site's Google sign-in button. */
|
|
189
|
+
googleClientId?: string | null;
|
|
190
|
+
/** The platform's Google sign-in page, opened in a popup — see `PublicSiteInfo`. */
|
|
191
|
+
googleSignInUrl?: string | null;
|
|
192
|
+
/** The Apple Services ID for the site's Apple sign-in — see `PublicSiteInfo`. */
|
|
193
|
+
appleClientId?: string | null;
|
|
194
|
+
/** The platform's Apple sign-in page, opened in a popup — see `PublicSiteInfo`. */
|
|
195
|
+
appleSignInUrl?: string | null;
|
|
196
|
+
settings?: Record<string, string>;
|
|
197
|
+
languages: PublicLanguage[];
|
|
198
|
+
}
|
|
199
|
+
/** The company as a *site*: the shape a page asks for by `getSiteInfo()`. */
|
|
200
|
+
export interface PublicSiteInfo {
|
|
201
|
+
siteName: string;
|
|
202
|
+
defaultLanguage: string;
|
|
203
|
+
languages: PublicLanguage[];
|
|
204
|
+
/**
|
|
205
|
+
* ISO 4217, the code every price on this site is in.
|
|
206
|
+
*
|
|
207
|
+
* A product carries an amount and no currency — the company's is the currency — so a page
|
|
208
|
+
* showing a price without this one is guessing, and the guess is always "$".
|
|
209
|
+
*/
|
|
210
|
+
currency?: string;
|
|
211
|
+
/**
|
|
212
|
+
* ISO 3166-1 alpha-2 country the shop trades in ("NZ"), null until it is set. A visitor from
|
|
213
|
+
* there reads the shop's own dollar as a bare "$"; anyone else is told whose dollar it is
|
|
214
|
+
* ("NZ$1.10"), and a dollar not the shop's always carries its code ("USD$1.10").
|
|
215
|
+
*/
|
|
216
|
+
countryCode?: string | null;
|
|
217
|
+
/**
|
|
218
|
+
* The country the visitor reading this page is in ("NZ"), from their request - null when it
|
|
219
|
+
* is not known (a static build, a browser that names no region). With `countryCode`: a visitor
|
|
220
|
+
* at home reads the shop's dollar as "$1.10", anyone else "NZ$1.10".
|
|
221
|
+
*/
|
|
222
|
+
visitorCountry?: string | null;
|
|
223
|
+
/** The sign to print beside an amount: "₽", "$", or the code where there is no sign. */
|
|
224
|
+
currencySymbol?: string;
|
|
225
|
+
/**
|
|
226
|
+
* Which side of the number that sign goes on, and it is a property of the CURRENCY rather
|
|
227
|
+
* than of the reader: the ruble trails ("1 000 ₽") and the dollar leads ("$1,000") whatever
|
|
228
|
+
* language the page is written in. `Intl` answers the other question — how an ENGLISH page
|
|
229
|
+
* writes a ruble — which is why this comes from the server instead.
|
|
230
|
+
*
|
|
231
|
+
* A trailing symbol is written with a space before it, a leading one without.
|
|
232
|
+
*/
|
|
233
|
+
currencySymbolPosition?: CurrencySymbolPosition;
|
|
234
|
+
/**
|
|
235
|
+
* The sales tax rate in percent (0: none), and whether the prices on this site already
|
|
236
|
+
* include it — for "Prices include 15% GST" on a page, before anything is in a basket.
|
|
237
|
+
*/
|
|
238
|
+
taxRate?: number;
|
|
239
|
+
taxInclusive?: boolean;
|
|
240
|
+
/** What the tax is called where the shop trades — GST, VAT, Sales tax. */
|
|
241
|
+
taxName?: string;
|
|
242
|
+
/**
|
|
243
|
+
* Whether to ask which location an order is for (`getLocations`): `never` - show no picker
|
|
244
|
+
* (a `locationId` sent anyway is not kept); `optional` - offer one; `required` - ask first:
|
|
245
|
+
* `createCheckout` without a `locationId` is refused.
|
|
246
|
+
*/
|
|
247
|
+
orderLocation: OrderLocationMode;
|
|
248
|
+
/**
|
|
249
|
+
* How customers may receive an order, in the order the shop offers them: `pickup` (takeaway),
|
|
250
|
+
* `reservation` and/or `delivery`. The hosted payment page asks when there is more than one (and,
|
|
251
|
+
* for delivery, takes the address and adds the fee); a page may also ask in the cart and pass
|
|
252
|
+
* the choice as `createCheckout({ orderType })`.
|
|
253
|
+
*/
|
|
254
|
+
orderTypes: OrderType[];
|
|
255
|
+
/**
|
|
256
|
+
* How guests book online (`getBookingSlots`, `createBooking`): `off` - no booking, hide any
|
|
257
|
+
* "Book" link; `table` a whole table; `seat` seats at a shared table; `time` a time only (no
|
|
258
|
+
* table, no plan).
|
|
259
|
+
*/
|
|
260
|
+
reservationMode?: "off" | "table" | "seat" | "time";
|
|
261
|
+
/**
|
|
262
|
+
* What a guest may book - `table`, `list` (an entry of the shop's list: a specialist, a room),
|
|
263
|
+
* `time` alone - the shop's main way first, the one `reservationMode` describes. With more than
|
|
264
|
+
* one, let the guest pick and pass it as `kind` to `getBookingSlots`, `getBookingPlan` and
|
|
265
|
+
* `createBooking`. Empty while reservations are off.
|
|
266
|
+
*/
|
|
267
|
+
reservationKinds: ReservationKind[];
|
|
268
|
+
/**
|
|
269
|
+
* @deprecated `reservationMode !== "off"` - worked out here for sites written before; the
|
|
270
|
+
* server no longer sends it.
|
|
271
|
+
*/
|
|
272
|
+
tableReservations?: boolean;
|
|
273
|
+
/**
|
|
274
|
+
* @deprecated Always true: signing in is always offered (`customerSignInMethods` says how).
|
|
275
|
+
* Kept for sites written before; the server no longer sends it.
|
|
276
|
+
*/
|
|
277
|
+
customerSignIn?: boolean;
|
|
278
|
+
/**
|
|
279
|
+
* Which ways to offer: `email` (`requestSignInCode` +
|
|
280
|
+
* `verifySignInCode`), `google` (`signInWithGoogle`) and `apple` (`signInWithApple`). A way
|
|
281
|
+
* that is off is refused.
|
|
282
|
+
*/
|
|
283
|
+
customerSignInMethods: {
|
|
284
|
+
email: boolean;
|
|
285
|
+
google: boolean;
|
|
286
|
+
apple: boolean;
|
|
287
|
+
};
|
|
288
|
+
/**
|
|
289
|
+
* Who sees the site. `public`: everybody. `signed_in`: signed-in customers only - the
|
|
290
|
+
* catalogue, cart, checkout and bookings refuse a guest (`PublicApiError` 401, code
|
|
291
|
+
* `customer_sign_in_required`), so show the sign-in instead of the menu.
|
|
292
|
+
*/
|
|
293
|
+
customerAccess: CustomerAccess;
|
|
294
|
+
/**
|
|
295
|
+
* Only a signed-in customer may book a table: `createBooking` rejects a guest (401). Ask them
|
|
296
|
+
* to sign in before the booking form.
|
|
297
|
+
*/
|
|
298
|
+
reservationRequiresSignIn: boolean;
|
|
299
|
+
/**
|
|
300
|
+
* What a reservation may be booked for: `off` nothing; `any` any product; `list` only the
|
|
301
|
+
* products the booked entry allows (each entry `getBookingSlots` offers lists its
|
|
302
|
+
* `productIds`).
|
|
303
|
+
*
|
|
304
|
+
* The booking window, the per-customer limit, a payment due at booking and the cancellation
|
|
305
|
+
* notice are the server's to apply and are not published here: `getBookingSlots` marks times
|
|
306
|
+
* outside the window unavailable and says `cancelHours`; `createBooking` refuses what the
|
|
307
|
+
* rules refuse (and answers `pending` with `payment` when the booking is paid for up front);
|
|
308
|
+
* each of the customer's bookings says `cancellableUntil`.
|
|
309
|
+
*/
|
|
310
|
+
reservationOrder?: "off" | "any" | "list";
|
|
311
|
+
/**
|
|
312
|
+
* How a booking's order may be paid when it is made: `order` - charged at once; `deferred` -
|
|
313
|
+
* the card held and charged when the shop accepts the booking. Both: let the guest choose and
|
|
314
|
+
* send it as `payment` to `createBooking`. Neither: paid at the visit.
|
|
315
|
+
*/
|
|
316
|
+
reservationPayment: PublicReservationPayment;
|
|
317
|
+
/**
|
|
318
|
+
* Only a signed-in customer may order: `createCheckout` rejects a guest (401, "Sign in to place
|
|
319
|
+
* an order"). Sign them in when they go to pay, then check out.
|
|
320
|
+
*/
|
|
321
|
+
orderRequiresSignIn: boolean;
|
|
322
|
+
/**
|
|
323
|
+
* A guest may follow a delivered order on the tracking page: `trackOrder({ code, email })` -
|
|
324
|
+
* the delivery's tracking number (`K7P-QX9-M2T`, in the order's emails) and the order's email.
|
|
325
|
+
* False: offer signing in instead (the account lists every order); `trackOrder` by number
|
|
326
|
+
* refuses.
|
|
327
|
+
*/
|
|
328
|
+
publicOrderTracking: boolean;
|
|
329
|
+
/**
|
|
330
|
+
* Money off for paying one way — `online` by card at checkout, `inStore` at the counter — or
|
|
331
|
+
* null for none. For the basket to SAY ("Save 10% paying online"): the customer chooses how to
|
|
332
|
+
* pay on the checkout page, which takes it off then; the basket's own total is before it.
|
|
333
|
+
*/
|
|
334
|
+
paymentDiscounts: PublicPaymentDiscounts;
|
|
335
|
+
/**
|
|
336
|
+
* The client id to render Google's sign-in button with (Google Identity Services). Null: Google
|
|
337
|
+
* sign-in is not configured on the platform — offer no Google button.
|
|
338
|
+
*/
|
|
339
|
+
googleClientId: string | null;
|
|
340
|
+
/**
|
|
341
|
+
* The platform's Google sign-in page. A site opens it in a popup (`?origin=<site origin>`) and
|
|
342
|
+
* receives `{ type: "salespoint:google-credential", credential }` by `postMessage` — Google's
|
|
343
|
+
* button is drawn there, on the one origin registered with Google, not on every site's. Null:
|
|
344
|
+
* offer no Google button.
|
|
345
|
+
*/
|
|
346
|
+
googleSignInUrl: string | null;
|
|
347
|
+
/**
|
|
348
|
+
* The Apple Services ID the platform's Apple sign-in page signs in with. Null: Apple sign-in is
|
|
349
|
+
* not configured on the platform — offer no Apple button.
|
|
350
|
+
*/
|
|
351
|
+
appleClientId: string | null;
|
|
352
|
+
/**
|
|
353
|
+
* The platform's Apple sign-in page. A site opens it in a popup (`?origin=<site origin>`, and
|
|
354
|
+
* `client=<appleClientId>`) and receives `{ type: "salespoint:apple-credential", credential,
|
|
355
|
+
* name }` by `postMessage` — pass both to `signInWithApple`. `name` is "First Last" on the
|
|
356
|
+
* first sign-in only (Apple sends it once), else null. Null: offer no Apple button.
|
|
357
|
+
*/
|
|
358
|
+
appleSignInUrl: string | null;
|
|
359
|
+
settings?: Record<string, string>;
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* A category. Only active ones are ever returned, so there is no `status`; the list comes
|
|
363
|
+
* back already in the author's order, so there is no `order` either.
|
|
364
|
+
*
|
|
365
|
+
* The optional parts are there only when asked for through `include` — which this client
|
|
366
|
+
* does by default, see `PublicCategoryInclude`.
|
|
367
|
+
*/
|
|
368
|
+
export interface PublicCategory {
|
|
369
|
+
id: string;
|
|
370
|
+
name: string;
|
|
371
|
+
/**
|
|
372
|
+
* The name the shop gave it, untranslated - the same in every language (`name` is in the
|
|
373
|
+
* page's). For links and anchors that must not change with the language. Absent from an
|
|
374
|
+
* API older than it.
|
|
375
|
+
*/
|
|
376
|
+
canonicalName?: string;
|
|
377
|
+
description?: string;
|
|
378
|
+
/** The parent category's id, or `null` for a root. A shop may have several roots. */
|
|
379
|
+
parentId: string | null;
|
|
380
|
+
createdAt?: string;
|
|
381
|
+
updatedAt?: string;
|
|
382
|
+
/** With `include: ["media"]`. */
|
|
383
|
+
media?: PublicMedia[];
|
|
384
|
+
/** With `include: ["count"]`: active products linked to this category. */
|
|
385
|
+
productCount?: number;
|
|
386
|
+
/** With `include: ["count"]`: active products here AND in every category beneath it. */
|
|
387
|
+
descendantProductCount?: number;
|
|
388
|
+
/** With `include: ["translations"]`: every enabled language, then field name. */
|
|
389
|
+
translations?: Record<string, Record<string, string>>;
|
|
390
|
+
}
|
|
391
|
+
/** One way a product is sold — see `PublicProduct.variants`. */
|
|
392
|
+
export interface PublicProductVariant {
|
|
393
|
+
id: string;
|
|
394
|
+
/** In the request language, falling back to the base name; `""` when the shop gave none. */
|
|
395
|
+
name: string;
|
|
396
|
+
/** What this variant costs: its own price, or the product's where it has none. A number, as
|
|
397
|
+
* `PublicProduct.price` is — this client converts it the same way. */
|
|
398
|
+
price?: number;
|
|
399
|
+
/** Whether it can be bought now. Show an unavailable one as sold out rather than hiding it. */
|
|
400
|
+
isAvailable: boolean;
|
|
401
|
+
order: number;
|
|
402
|
+
/** The variant's own first image, when it has one; otherwise use the product's. */
|
|
403
|
+
image?: string;
|
|
404
|
+
/** The variant-scoped settings, described like the product's: the variant's own value, or
|
|
405
|
+
* the product's where the variant has none. */
|
|
406
|
+
settings: Record<string, PublicProductSetting>;
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* The optional parts of a category. `count` is `productCount` + `descendantProductCount`.
|
|
410
|
+
*
|
|
411
|
+
* The API returns none of them unless asked. This client asks for ALL of them when a caller
|
|
412
|
+
* passes no `include`, so a page written before `include` existed renders as it did; pass a
|
|
413
|
+
* narrower list (or `[]`) to trim the response.
|
|
414
|
+
*/
|
|
415
|
+
export type PublicCategoryInclude = "translations" | "media" | "count";
|
|
416
|
+
export interface PublicProductCategoryRef {
|
|
417
|
+
id: string;
|
|
418
|
+
name?: string;
|
|
419
|
+
}
|
|
420
|
+
/** What kind of value a product setting holds — and so, how a page renders it. */
|
|
421
|
+
export type PublicProductSettingType = "text" | "richtext" | "boolean" | "number" | "range"
|
|
422
|
+
/** A day, `"YYYY-MM-DD"`. */
|
|
423
|
+
| "date" | "dictionary" | "dictionary_multi";
|
|
424
|
+
/** A `range` value: where the product sits, and the scale it sits on. */
|
|
425
|
+
export interface PublicProductSettingRange {
|
|
426
|
+
value: number;
|
|
427
|
+
max: number;
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* One of a product's settings, described.
|
|
431
|
+
*
|
|
432
|
+
* The API used to answer a bare `{ KEY: value }` bag, which left a page guessing at all
|
|
433
|
+
* three things it needs: a `4` could be a count, a rating out of five or a number of
|
|
434
|
+
* minutes; a `"Large"` could be free text or one entry of a list the shop curates; and an
|
|
435
|
+
* absent key could mean "this shop does not use the field" or "nobody filled it in". None of
|
|
436
|
+
* those is answerable from a value, and a page cannot ask the catalogue — `getProductSettings`
|
|
437
|
+
* describes the SHOP, not this product.
|
|
438
|
+
*/
|
|
439
|
+
export interface PublicProductSetting {
|
|
440
|
+
type: PublicProductSettingType;
|
|
441
|
+
/**
|
|
442
|
+
* What the product holds, or `""` when it holds nothing. The key is still there: a shop
|
|
443
|
+
* that shows a field nobody filled in renders differently from a shop without the field.
|
|
444
|
+
*
|
|
445
|
+
* `range` answers `{ value, max }`; `dictionary_multi` answers the entry NAMES, not ids.
|
|
446
|
+
*/
|
|
447
|
+
value: string | number | boolean | string[] | PublicProductSettingRange | "";
|
|
448
|
+
/**
|
|
449
|
+
* `dictionary_multi` only: the entries of `value` the customer may not take off the product -
|
|
450
|
+
* an ingredient the dish is not made without. NAMES, as `value` holds them; absent when none.
|
|
451
|
+
* Show them kept and do not offer to leave them off: a line leaving one off is refused.
|
|
452
|
+
*/
|
|
453
|
+
required?: string[];
|
|
454
|
+
/** The list the value is an entry of, as the shop writes it. Only on the two `dictionary`
|
|
455
|
+
* types — it is what tells one shop's "Size" (pizza sizes) from another's (bottle sizes).
|
|
456
|
+
* This is the one to PRINT; it is translated and reworded, so fetch with `listIdentifier`. */
|
|
457
|
+
listName?: string;
|
|
458
|
+
/**
|
|
459
|
+
* The same list by identifier — what to FETCH it with:
|
|
460
|
+
* `getDictionary({ identifier: setting.listIdentifier })`.
|
|
461
|
+
*
|
|
462
|
+
* The handle the shop gave the list. Unlike the name it does not move, so a page that reads
|
|
463
|
+
* a product's sizes or add-ons through it keeps working when the shop retitles the list or
|
|
464
|
+
* translates it. Absent on a list the shop has not given one, and on a list the shop keeps
|
|
465
|
+
* private (not "Visible on site") - there is nothing a page could fetch with it.
|
|
466
|
+
*/
|
|
467
|
+
listIdentifier?: string;
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* One setting as the SHOP has it — the catalogue, not a product's value.
|
|
471
|
+
*
|
|
472
|
+
* `getProductSettings()` answers a list of these: what fields this shop keeps on its
|
|
473
|
+
* products, what kind of value each holds, and which of them it actually shows. A page uses
|
|
474
|
+
* it to lay out a form or a spec table before it has a product in hand; for one product's
|
|
475
|
+
* values, read `PublicProduct.settings`, which describes the same keys with values attached.
|
|
476
|
+
*
|
|
477
|
+
* Only the fields the shop has switched on AND lets websites read are listed. A disabled or
|
|
478
|
+
* private field (a SKU, a bar code, a cost) is not here, and its values never appear on a product.
|
|
479
|
+
*/
|
|
480
|
+
export interface PublicProductSettingDefinition {
|
|
481
|
+
/** What the value is stored under — `IS_VEGETARIAN`, `SIZE`, `CUSTOM_ROAST`. */
|
|
482
|
+
key: string;
|
|
483
|
+
/** What to call it on the page — "Size", "Calories per serving (kcal)". */
|
|
484
|
+
label?: string;
|
|
485
|
+
type: PublicProductSettingType;
|
|
486
|
+
/** Section it is listed under, when the shop said. */
|
|
487
|
+
groupKey?: string;
|
|
488
|
+
/** Unit shown after the value, e.g. "g". Never on the list types. */
|
|
489
|
+
suffix?: string;
|
|
490
|
+
/** The list it draws from, on the two `dictionary` types. */
|
|
491
|
+
dictionaryId?: string;
|
|
492
|
+
/** What that list is called. Absent on a list nobody has named. */
|
|
493
|
+
listName?: string;
|
|
494
|
+
/** Top of the scale, on `range` only. */
|
|
495
|
+
rangeMax?: number;
|
|
496
|
+
}
|
|
497
|
+
export interface PublicProduct {
|
|
498
|
+
id: string;
|
|
499
|
+
/**
|
|
500
|
+
* The shop's own number for the product - link it as its key, `PR-12`
|
|
501
|
+
* (`/menu/PR-12`); `getProduct({ name: "PR-12" })` finds it by that key.
|
|
502
|
+
*/
|
|
503
|
+
productNumber: number;
|
|
504
|
+
name: string;
|
|
505
|
+
description?: string;
|
|
506
|
+
story?: string;
|
|
507
|
+
/**
|
|
508
|
+
* Always a number here, and worth knowing why that is not free: the API answers with a
|
|
509
|
+
* STRING (`"13.00"`), because the column is a Postgres decimal. `@estoreclub/api` converts it
|
|
510
|
+
* so this type is true — anything reading the endpoint directly must do the same.
|
|
511
|
+
*/
|
|
512
|
+
price?: number;
|
|
513
|
+
/** The product's type, or `null` for a flexible product. */
|
|
514
|
+
schemaId?: string | null;
|
|
515
|
+
/** A product or a service: chosen when the shop sells both, else the one kind it sells. */
|
|
516
|
+
kind?: "product" | "service";
|
|
517
|
+
createdAt?: string;
|
|
518
|
+
/** With `include: ["media"]`. */
|
|
519
|
+
media?: PublicMedia[];
|
|
520
|
+
/**
|
|
521
|
+
* True when the shop stops selling at zero (its sales rules) and this product has none left.
|
|
522
|
+
* Absent otherwise — including for a product nobody counts. Show it as sold out: adding it to
|
|
523
|
+
* a basket is refused.
|
|
524
|
+
*/
|
|
525
|
+
soldOut?: boolean;
|
|
526
|
+
/**
|
|
527
|
+
* What customers' stars come to: the average (one decimal), how many rated, and the top of
|
|
528
|
+
* the scale. Only while the shop has customers vote with stars, and only once somebody has.
|
|
529
|
+
*/
|
|
530
|
+
customerRating?: {
|
|
531
|
+
average: number;
|
|
532
|
+
count: number;
|
|
533
|
+
max: number;
|
|
534
|
+
};
|
|
535
|
+
/**
|
|
536
|
+
* What customers' likes come to: how many liked it and how many disliked it. Only while the
|
|
537
|
+
* shop has customers vote with likes (`dislikes` is 0 where it takes likes only), and only once
|
|
538
|
+
* somebody has.
|
|
539
|
+
*/
|
|
540
|
+
customerLikes?: {
|
|
541
|
+
likes: number;
|
|
542
|
+
dislikes: number;
|
|
543
|
+
};
|
|
544
|
+
/**
|
|
545
|
+
* Where it stands among the shop's best sellers: 1 for the most units sold in paid,
|
|
546
|
+
* non-cancelled orders over the last 30 days, 2 for the next (ties share a rank) - the SALES
|
|
547
|
+
* rank; `sortBy: "popularity"` leads with ratings and only then follows it. A rank, never the
|
|
548
|
+
* units. Absent for a product that sold nothing in that time.
|
|
549
|
+
*/
|
|
550
|
+
popularRank?: number;
|
|
551
|
+
/** With `include: ["categories"]`. Active categories only. */
|
|
552
|
+
categories?: PublicProductCategoryRef[];
|
|
553
|
+
/** With `include: ["settings"]`. Every setting the shop shows, described — see
|
|
554
|
+
* `PublicProductSetting`. Keys the company has switched off are absent, even where the
|
|
555
|
+
* product's type lists them; keys this product has not filled in carry an empty value. */
|
|
556
|
+
settings?: Record<string, PublicProductSetting>;
|
|
557
|
+
/** With `include: ["translations"]`: every enabled language, then field name. */
|
|
558
|
+
translations?: Record<string, Record<string, string>>;
|
|
559
|
+
/**
|
|
560
|
+
* The product's variants — its sizes, crusts, volumes — in the shop's order. Present with
|
|
561
|
+
* `include: ["settings"]`, and only on a product that has any.
|
|
562
|
+
*
|
|
563
|
+
* A product WITH variants is bought as one of them: `addCartItem` needs the variant's `id`
|
|
564
|
+
* as `variantId`, and the cart and checkout then charge that variant's price and discount.
|
|
565
|
+
*/
|
|
566
|
+
variants?: PublicProductVariant[];
|
|
567
|
+
}
|
|
568
|
+
/**
|
|
569
|
+
* The optional parts of a product in a LISTING. Only active products are returned, so there
|
|
570
|
+
* is no `status`.
|
|
571
|
+
*
|
|
572
|
+
* As with categories, the API returns none unless asked and this client asks for all of them
|
|
573
|
+
* when a caller passes no `include`. `settings` is by far the largest part — a page that only
|
|
574
|
+
* shows names and prices should leave it out.
|
|
575
|
+
*
|
|
576
|
+
* One product read by id or name (`getProduct`) always carries everything.
|
|
577
|
+
*/
|
|
578
|
+
export type PublicProductInclude = "translations" | "media" | "categories" | "settings";
|
|
579
|
+
/** One field every entry of a list carries, so a page knows how to read the values. */
|
|
580
|
+
/** What a list column holds. `entry` is the id of an entry of another list. */
|
|
581
|
+
export type PublicDictionaryColumnType = "text" | "number" | "money" | "date" | "translated_text" | "product" | "category" | "image" | "boolean" | "entry";
|
|
582
|
+
export interface PublicDictionaryColumn {
|
|
583
|
+
key: string;
|
|
584
|
+
label?: string;
|
|
585
|
+
type: PublicDictionaryColumnType;
|
|
586
|
+
/** For `entry`: the list the ids belong to - `getDictionary({ id })` names them. */
|
|
587
|
+
referenceDictionaryId?: string;
|
|
588
|
+
/**
|
|
589
|
+
* Several values of the type: the value is an array (several numbers, images, entry ids).
|
|
590
|
+
* Never for `boolean` or `translated_text`.
|
|
591
|
+
*/
|
|
592
|
+
multiple?: boolean;
|
|
593
|
+
}
|
|
594
|
+
export interface PublicDictionaryEntry {
|
|
595
|
+
id: string;
|
|
596
|
+
/** Resolved to the language the site is read in. */
|
|
597
|
+
name: string;
|
|
598
|
+
/**
|
|
599
|
+
* Column values by key. A `money` column is a signed number of the shop's currency; a
|
|
600
|
+
* `multiple` column's value is an array of its type's values.
|
|
601
|
+
*/
|
|
602
|
+
values: Record<string, string | number | boolean | string[] | number[]>;
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* A list the shop keeps — its sizes, its add-ons, what its kitchen cooks with.
|
|
606
|
+
*
|
|
607
|
+
* The other half of `product.settings`: a product says WHICH size it is and which add-ons it
|
|
608
|
+
* offers, this says what the shop's sizes and add-ons ARE — every entry, and the columns they
|
|
609
|
+
* carry. An add-on's surcharge lives on the entry, so a page pricing "large with extra
|
|
610
|
+
* mozzarella" needs both halves and only one of them rides on a product.
|
|
611
|
+
*/
|
|
612
|
+
export interface PublicDictionary {
|
|
613
|
+
id: string;
|
|
614
|
+
/**
|
|
615
|
+
* The shop's own machine name for the list — `add_ons`, `pizza_sizes`. Set once and never
|
|
616
|
+
* changed, which is why a page should read by it rather than by the label.
|
|
617
|
+
*/
|
|
618
|
+
identifier?: string;
|
|
619
|
+
/** What the shop calls it, in the language asked for. */
|
|
620
|
+
label: string;
|
|
621
|
+
description?: string;
|
|
622
|
+
columns: PublicDictionaryColumn[];
|
|
623
|
+
entries: PublicDictionaryEntry[];
|
|
624
|
+
}
|
|
625
|
+
/**
|
|
626
|
+
* A list without its entries — what `listDictionaries()` answers. Only the lists the shop
|
|
627
|
+
* marked "Visible on site", and only their public columns.
|
|
628
|
+
*/
|
|
629
|
+
export type PublicDictionarySummary = Omit<PublicDictionary, "entries">;
|
|
630
|
+
/**
|
|
631
|
+
* How a single read names its row: by `id`, or by what it is called. Exactly one — the
|
|
632
|
+
* client refuses both or neither before anything leaves the process.
|
|
633
|
+
*/
|
|
634
|
+
export type ByIdOrName = {
|
|
635
|
+
/** The row's id (a UUID), e.g. from a listing. */
|
|
636
|
+
id: string;
|
|
637
|
+
name?: never;
|
|
638
|
+
} | {
|
|
639
|
+
/**
|
|
640
|
+
* What it is called. Matched case-insensitively on the trimmed text, so a page need
|
|
641
|
+
* not reproduce the shop's capitalisation.
|
|
642
|
+
*/
|
|
643
|
+
name: string;
|
|
644
|
+
id?: never;
|
|
645
|
+
};
|
|
646
|
+
/**
|
|
647
|
+
* A list by IDENTIFIER, by id, or by its label. Exactly one.
|
|
648
|
+
*
|
|
649
|
+
* `identifier` is the one to write a page against: the shop sets it once and it never changes.
|
|
650
|
+
* The label — `"Add-ons"`, `"Pizza sizes"` — still works and survives a retitling in another
|
|
651
|
+
* case, but it is translated and reworded, and a page reading by it breaks the day the shop
|
|
652
|
+
* tidies it up.
|
|
653
|
+
*/
|
|
654
|
+
export type GetDictionaryParams = {
|
|
655
|
+
/** The shop's machine name for the list, e.g. `"add_ons"`. */
|
|
656
|
+
identifier: string;
|
|
657
|
+
id?: never;
|
|
658
|
+
name?: never;
|
|
659
|
+
} | (ByIdOrName & {
|
|
660
|
+
identifier?: never;
|
|
661
|
+
});
|
|
662
|
+
/** Products are paginated; categories are not. The asymmetry is the API's, not ours. */
|
|
663
|
+
export interface PaginationMetadata {
|
|
664
|
+
page: number;
|
|
665
|
+
limit: number;
|
|
666
|
+
hasNext: boolean;
|
|
667
|
+
}
|
|
668
|
+
export interface Paginated<T> {
|
|
669
|
+
data: T[];
|
|
670
|
+
pagination: PaginationMetadata;
|
|
671
|
+
}
|
|
672
|
+
export interface ListCategoriesParams {
|
|
673
|
+
search?: string;
|
|
674
|
+
/** Optional parts to include. Omitted → all of them; `[]` → none. */
|
|
675
|
+
include?: PublicCategoryInclude[];
|
|
676
|
+
/**
|
|
677
|
+
* At most this many.
|
|
678
|
+
*
|
|
679
|
+
* Applied HERE, not by the server: the categories route takes no paging, while the
|
|
680
|
+
* products one does. Callers write the two calls side by side and reasonably expect the
|
|
681
|
+
* same parameter to mean something in both, so it is honoured rather than ignored — a
|
|
682
|
+
* category list is tens of rows, so trimming the answer costs nothing.
|
|
683
|
+
*/
|
|
684
|
+
limit?: number;
|
|
685
|
+
}
|
|
686
|
+
/**
|
|
687
|
+
* One category by `id`, or by what it is called — `"Wood-fired"`.
|
|
688
|
+
*
|
|
689
|
+
* A name is matched case-insensitively on the trimmed text, against the category's own name
|
|
690
|
+
* and its translations, so a page read in German may ask for the German heading. Names are
|
|
691
|
+
* not unique: where several match, the oldest is returned.
|
|
692
|
+
*/
|
|
693
|
+
export type GetCategoryParams = ByIdOrName & {
|
|
694
|
+
/** Optional parts to include. Omitted → all of them; `[]` → none. */
|
|
695
|
+
include?: PublicCategoryInclude[];
|
|
696
|
+
};
|
|
697
|
+
/** One product by `id`, or by what it is called — matched the way a category's name is. */
|
|
698
|
+
export type GetProductParams = ByIdOrName;
|
|
699
|
+
export interface ListProductsParams {
|
|
700
|
+
/** A category UUID. Mutually exclusive with `categoryName`. */
|
|
701
|
+
categoryId?: string;
|
|
702
|
+
/** A category slug. The API's own spelling for what a page may call `categoryUniqueName`. */
|
|
703
|
+
categoryName?: string;
|
|
704
|
+
/** Only products filed under no category at all. */
|
|
705
|
+
categoryEmpty?: boolean;
|
|
706
|
+
search?: string;
|
|
707
|
+
/** 1-indexed, as the API counts. */
|
|
708
|
+
page?: number;
|
|
709
|
+
limit?: number;
|
|
710
|
+
tags?: string;
|
|
711
|
+
/**
|
|
712
|
+
* How the list is ordered. `custom` — the shop's own arrangement — is the default.
|
|
713
|
+
*
|
|
714
|
+
* `popularity` puts RATED products first, best rated first: by the customers' votes while the
|
|
715
|
+
* shop takes them (stars as the average over the scale, likes as the share of likes; with `up`
|
|
716
|
+
* voting, liked products first), else by the shop's own RATING setting over its scale. Equal
|
|
717
|
+
* ratings and unrated products then follow by units sold in paid, non-cancelled orders over the
|
|
718
|
+
* last `popularityDays`.
|
|
719
|
+
*
|
|
720
|
+
* `discount` puts the biggest discount on RIGHT NOW first: what comes off one unit of the
|
|
721
|
+
* product's own price - its DISCOUNT_RULE while that rule applies, else its DISCOUNT setting -
|
|
722
|
+
* the biggest percentage first, then the most saved. Products with no discount come last.
|
|
723
|
+
*
|
|
724
|
+
* Every order breaks ties by the shop's arrangement, so a shop with no ratings, sales or deals
|
|
725
|
+
* yet gets its own order back.
|
|
726
|
+
*/
|
|
727
|
+
sortBy?: ProductSort;
|
|
728
|
+
/**
|
|
729
|
+
* Defaults to `DESC` for `popularity` and `discount` (the most of it first) and `ASC` for
|
|
730
|
+
* everything else. Unrated (popularity) and undiscounted (discount) products stay last either
|
|
731
|
+
* way.
|
|
732
|
+
*/
|
|
733
|
+
sortOrder?: "ASC" | "DESC";
|
|
734
|
+
/** How many days back `popularity` counts sales over: 1–365, 30 when omitted. */
|
|
735
|
+
popularityDays?: number;
|
|
736
|
+
/** Optional parts to include. Omitted → all of them; `[]` → none. */
|
|
737
|
+
include?: PublicProductInclude[];
|
|
738
|
+
}
|
|
739
|
+
/**
|
|
740
|
+
* When a deal is on, on the shop's clock. A deal with no schedule is on at every hour of the
|
|
741
|
+
* days it is valid.
|
|
742
|
+
*/
|
|
743
|
+
export interface PublicDealSchedule {
|
|
744
|
+
/** IANA zone the windows are read in, e.g. `"Pacific/Auckland"`. */
|
|
745
|
+
timeZone: string;
|
|
746
|
+
windows: Array<{
|
|
747
|
+
/** ISO weekdays, 1 = Monday … 7 = Sunday. */
|
|
748
|
+
days: number[];
|
|
749
|
+
/** `HH:MM`, inclusive. */
|
|
750
|
+
from: string;
|
|
751
|
+
/** `HH:MM`, exclusive. Not after `from`: runs past midnight. */
|
|
752
|
+
until: string;
|
|
753
|
+
}>;
|
|
754
|
+
}
|
|
755
|
+
/**
|
|
756
|
+
* How a combo's `price` is read:
|
|
757
|
+
*
|
|
758
|
+
* - `fixed_price`: the combo costs `price`, plus each pick's `surcharge`.
|
|
759
|
+
* - `percent_off`: the picks at their own prices, `price`% off.
|
|
760
|
+
* - `amount_off`: the picks at their own prices, `price` off — never below zero.
|
|
761
|
+
*/
|
|
762
|
+
export type ComboPriceKind = "fixed_price" | "percent_off" | "amount_off";
|
|
763
|
+
/** A product variant a combo option may be filled with — when the option leaves it open. */
|
|
764
|
+
export interface PublicComboVariant {
|
|
765
|
+
id: string;
|
|
766
|
+
name: string;
|
|
767
|
+
/** False for a variant not on sale now: show it, but do not let it be picked. */
|
|
768
|
+
isAvailable: boolean;
|
|
769
|
+
}
|
|
770
|
+
/** One product that may fill a slot. */
|
|
771
|
+
export interface PublicComboSlotOption {
|
|
772
|
+
productId: string;
|
|
773
|
+
name: string;
|
|
774
|
+
/** The one variant this option offers, or null for "any of the product's variants". */
|
|
775
|
+
variantId: string | null;
|
|
776
|
+
variantName: string | null;
|
|
777
|
+
/** When `variantId` is null and the product has variants: the ones to choose from. */
|
|
778
|
+
variants?: PublicComboVariant[];
|
|
779
|
+
/** Added to a `fixed_price` combo for this pick, in major units. */
|
|
780
|
+
surcharge: number;
|
|
781
|
+
}
|
|
782
|
+
/** A place in the combo — "a pizza", "two drinks" — and what may fill it. */
|
|
783
|
+
export interface PublicComboSlot {
|
|
784
|
+
id: string;
|
|
785
|
+
name: string;
|
|
786
|
+
/** How many picks the slot takes. */
|
|
787
|
+
quantity: number;
|
|
788
|
+
options: PublicComboSlotOption[];
|
|
789
|
+
}
|
|
790
|
+
/**
|
|
791
|
+
* A combo on sale now: slots the shopper fills from a list of products, at a price.
|
|
792
|
+
*
|
|
793
|
+
* Only combos that are active, inside their dates and inside a weekly window AT THE MOMENT OF
|
|
794
|
+
* THE REQUEST are listed, and one with a slot no product on sale can fill is left out — so a
|
|
795
|
+
* page can show everything it is given. Add one to the cart with `addCartItem({ comboId,
|
|
796
|
+
* picks })`.
|
|
797
|
+
*/
|
|
798
|
+
export interface PublicCombo {
|
|
799
|
+
id: string;
|
|
800
|
+
name: string;
|
|
801
|
+
description?: string;
|
|
802
|
+
priceKind: ComboPriceKind;
|
|
803
|
+
/** Read by `priceKind`: the price before surcharges, the percentage off, or the amount off. */
|
|
804
|
+
price: number;
|
|
805
|
+
/** The cheapest way to fill it, in major units — for "from 9.90" on a menu. */
|
|
806
|
+
fromPrice: number;
|
|
807
|
+
/** ISO timestamp it stops being sold, or null when open-ended. */
|
|
808
|
+
validUntil: string | null;
|
|
809
|
+
schedule: PublicDealSchedule | null;
|
|
810
|
+
/** The categories the shop displays it in — e.g. a lunch combo among the pizzas. */
|
|
811
|
+
categoryIds: string[];
|
|
812
|
+
/**
|
|
813
|
+
* The combo's own pictures, cover first — the deal photographed as a set. Empty when the shop
|
|
814
|
+
* has none: show the combo by its picks' photos instead.
|
|
815
|
+
*/
|
|
816
|
+
images: {
|
|
817
|
+
url: string;
|
|
818
|
+
}[];
|
|
819
|
+
slots: PublicComboSlot[];
|
|
820
|
+
}
|
|
821
|
+
export interface ListCombosParams {
|
|
822
|
+
/** Only the combos the shop displays in this category. */
|
|
823
|
+
categoryId?: string;
|
|
824
|
+
}
|
|
825
|
+
/**
|
|
826
|
+
* The ways a discount rule prices the units it applies to:
|
|
827
|
+
*
|
|
828
|
+
* - `percent_off`: every unit costs `value`% less.
|
|
829
|
+
* - `amount_off`: every unit costs `value` less, never below zero.
|
|
830
|
+
* - `fixed_price`: every unit costs `value`, when that is less than its price.
|
|
831
|
+
* - `buy_x_get_y`: for every `buyQuantity` bought, the next `getQuantity` cost `value` each
|
|
832
|
+
* (`0` is free). The cheapest units of each group are the ones discounted.
|
|
833
|
+
* - `bundle_price`: every `buyQuantity` units together cost `value`.
|
|
834
|
+
*/
|
|
835
|
+
export type DiscountRuleKind = "percent_off" | "amount_off" | "fixed_price" | "buy_x_get_y" | "bundle_price";
|
|
836
|
+
/**
|
|
837
|
+
* A discount rule on now — for a page to badge the products it targets ("2 for 1", "-20%").
|
|
838
|
+
*
|
|
839
|
+
* For DISPLAY: which rule a cart unit actually takes is decided when the cart is priced, and
|
|
840
|
+
* the cart's `discounts` say what was taken off.
|
|
841
|
+
*/
|
|
842
|
+
export interface PublicDiscountRule {
|
|
843
|
+
id: string;
|
|
844
|
+
name: string;
|
|
845
|
+
description?: string;
|
|
846
|
+
kind: DiscountRuleKind;
|
|
847
|
+
/** A percentage for `percent_off`; money in major units for every other kind. */
|
|
848
|
+
value: number;
|
|
849
|
+
buyQuantity: number | null;
|
|
850
|
+
getQuantity: number | null;
|
|
851
|
+
validUntil: string | null;
|
|
852
|
+
schedule: PublicDealSchedule | null;
|
|
853
|
+
/** What it applies to: these products, and every product in these categories. */
|
|
854
|
+
productIds: string[];
|
|
855
|
+
categoryIds: string[];
|
|
856
|
+
}
|
|
857
|
+
/** The orders `getProducts` can list in. */
|
|
858
|
+
export type ProductSort = "custom" | "name" | "price" | "popularity" | "discount";
|
|
859
|
+
/**
|
|
860
|
+
* A basket, held by the server.
|
|
861
|
+
*
|
|
862
|
+
* `cartId` is the CREDENTIAL as well as the identifier — there is no visitor account, so
|
|
863
|
+
* whoever holds it holds the cart. Keep it out of anything a page renders, and out of a URL a
|
|
864
|
+
* visitor might share.
|
|
865
|
+
*/
|
|
866
|
+
export interface PublicCart {
|
|
867
|
+
cartId: string;
|
|
868
|
+
workspace: Workspace;
|
|
869
|
+
items: PublicCartItem[];
|
|
870
|
+
/** Units across every line, for a badge. */
|
|
871
|
+
count: number;
|
|
872
|
+
/**
|
|
873
|
+
* Sum of price x quantity at CURRENT prices — each line's variant price where it has one —
|
|
874
|
+
* before any discount.
|
|
875
|
+
*
|
|
876
|
+
* The server does not know what a site charges for a size or a topping — that lives in
|
|
877
|
+
* `variant`, which it stores and never reads — so a site with its own options has to total
|
|
878
|
+
* the lines itself. This is the floor, not the bill.
|
|
879
|
+
*/
|
|
880
|
+
subtotal: number;
|
|
881
|
+
/** Everything the shop's deals took off, in major units. */
|
|
882
|
+
discount: number;
|
|
883
|
+
/** `subtotal` less `discount`, plus tax when it is added on top — what the server will charge. */
|
|
884
|
+
total: number;
|
|
885
|
+
/**
|
|
886
|
+
* The sales tax in it, in major units: inside `total` when `taxInclusive` (show "incl. 15%
|
|
887
|
+
* tax"), added to it otherwise. 0 when the shop charges none.
|
|
888
|
+
*/
|
|
889
|
+
tax: number;
|
|
890
|
+
/** The shop's tax rate, in percent. 0: no tax. */
|
|
891
|
+
taxRate: number;
|
|
892
|
+
/** True: prices include the tax. False: it is added on top of them. */
|
|
893
|
+
taxInclusive: boolean;
|
|
894
|
+
/** What the tax is called where the shop trades — GST, VAT, Sales tax. Label the tax line with it. */
|
|
895
|
+
taxName: string;
|
|
896
|
+
/** The rules that took money off the cart as a whole, and how much each. */
|
|
897
|
+
discounts: PublicCartDiscount[];
|
|
898
|
+
/**
|
|
899
|
+
* The table booking this basket is ordered for (`setCartBooking`), with what its booking fee
|
|
900
|
+
* adds to paying it; null for an ordinary basket.
|
|
901
|
+
*/
|
|
902
|
+
booking: PublicCartBooking | null;
|
|
903
|
+
}
|
|
904
|
+
/** The booking a basket is ordered for, and its fee - see `PublicCart.booking`. */
|
|
905
|
+
export interface PublicCartBooking {
|
|
906
|
+
bookingId: string;
|
|
907
|
+
/** The shop's booking fee for this party, in major units; 0 when none is paid with an order. */
|
|
908
|
+
fee: number;
|
|
909
|
+
/**
|
|
910
|
+
* The fee counts towards the order: it is a minimum spend - an order of at least `fee` pays
|
|
911
|
+
* no fee, a smaller one pays the difference.
|
|
912
|
+
*/
|
|
913
|
+
feeIsDeposit: boolean;
|
|
914
|
+
/**
|
|
915
|
+
* What paying THIS basket adds for the booking, in major units, on top of `total`: the whole
|
|
916
|
+
* fee for an empty basket, the shortfall or 0 for a deposit, 0 once the fee is paid.
|
|
917
|
+
*/
|
|
918
|
+
charged: number;
|
|
919
|
+
/**
|
|
920
|
+
* Of a deposit, the part the basket covers, in major units - shown as the fee and taken off,
|
|
921
|
+
* so the fee is seen charged and removed. `charged` + `included` is the whole fee. Absent from
|
|
922
|
+
* servers before it.
|
|
923
|
+
*/
|
|
924
|
+
included?: number;
|
|
925
|
+
}
|
|
926
|
+
/** One deal, and what it took off a line or the cart. */
|
|
927
|
+
export interface PublicCartDiscount {
|
|
928
|
+
ruleId: string;
|
|
929
|
+
name: string;
|
|
930
|
+
/** In major units. */
|
|
931
|
+
amount: number;
|
|
932
|
+
}
|
|
933
|
+
/** One product picked into a combo line. */
|
|
934
|
+
export interface PublicCartComboPick {
|
|
935
|
+
slotId: string;
|
|
936
|
+
slotName: string;
|
|
937
|
+
productId: string;
|
|
938
|
+
name: string;
|
|
939
|
+
variantId: string | null;
|
|
940
|
+
variantName: string | null;
|
|
941
|
+
/** Added to the combo's price for this pick, in major units. */
|
|
942
|
+
surcharge: number;
|
|
943
|
+
/** The site's own configuration for the pick, as on a product line. */
|
|
944
|
+
variant?: string;
|
|
945
|
+
}
|
|
946
|
+
/** What makes a line a combo: which one, and what fills it. The line's `name` is the combo's. */
|
|
947
|
+
export interface PublicCartCombo {
|
|
948
|
+
comboId: string;
|
|
949
|
+
picks: PublicCartComboPick[];
|
|
950
|
+
}
|
|
951
|
+
export interface PublicCartItem {
|
|
952
|
+
/** Identifies the LINE, which is what quantity changes and removals address. */
|
|
953
|
+
cartItemId: string;
|
|
954
|
+
/** The product on a product line. Absent on a combo line — read `combo` there. */
|
|
955
|
+
productId?: string;
|
|
956
|
+
/** Present on a combo line: the combo and every pick in it. */
|
|
957
|
+
combo?: PublicCartCombo;
|
|
958
|
+
/** What deals took off this line, in major units, and which ones. */
|
|
959
|
+
discount: number;
|
|
960
|
+
discounts: PublicCartDiscount[];
|
|
961
|
+
/** (Price + `addOns`) × quantity less `discount`. */
|
|
962
|
+
total: number;
|
|
963
|
+
/** Why the line can no longer be bought (sold out, deal ended) — absent when it can. */
|
|
964
|
+
unavailable?: string;
|
|
965
|
+
name: string;
|
|
966
|
+
/** As it stands now, not as it stood when the line was added. Without the extras. */
|
|
967
|
+
price?: number;
|
|
968
|
+
/**
|
|
969
|
+
* What the chosen extras add to one unit, at the prices in the shop's lists - charged at
|
|
970
|
+
* checkout, not discounted. Absent when nothing extra was chosen.
|
|
971
|
+
*/
|
|
972
|
+
addOns?: number;
|
|
973
|
+
image?: string;
|
|
974
|
+
quantity: number;
|
|
975
|
+
/** The product variant this line is, when the product has variants. */
|
|
976
|
+
variantId: string | null;
|
|
977
|
+
/** That variant's name in the request language, for the basket row. */
|
|
978
|
+
variantName: string | null;
|
|
979
|
+
/** Whatever the site put there. Opaque to the server; parse it back yourself. */
|
|
980
|
+
variant: string;
|
|
981
|
+
}
|
|
982
|
+
/**
|
|
983
|
+
* Every cart call carries the id explicitly.
|
|
984
|
+
*
|
|
985
|
+
* The server would accept the cookie it set instead, and a browser on the same site would be
|
|
986
|
+
* fine. A SERVER component would not: it has no cookie jar, and would silently read whichever
|
|
987
|
+
* cart the process last touched. Passing the id makes the call mean the same thing wherever it
|
|
988
|
+
* runs.
|
|
989
|
+
*/
|
|
990
|
+
export interface GetCartParams {
|
|
991
|
+
cartId: string;
|
|
992
|
+
}
|
|
993
|
+
/**
|
|
994
|
+
* Add a product — or a combo, with what fills it. Exactly one of `productId` and `comboId`.
|
|
995
|
+
*/
|
|
996
|
+
export interface AddCartItemParams extends GetCartParams {
|
|
997
|
+
productId?: string;
|
|
998
|
+
/** A combo from `getCombos`; `picks` then fill every one of its slots. */
|
|
999
|
+
comboId?: string;
|
|
1000
|
+
/** One per unit a slot takes: a slot of `quantity: 2` takes two picks. */
|
|
1001
|
+
picks?: ComboPick[];
|
|
1002
|
+
/** Defaults to 1. Clamped, floored, and rejected if it is not a number. */
|
|
1003
|
+
quantity?: number;
|
|
1004
|
+
/**
|
|
1005
|
+
* Which of the product's variants — `PublicProduct.variants[].id`. Required for a product
|
|
1006
|
+
* that has variants, refused for one that has none. The line is then priced as that variant:
|
|
1007
|
+
* its price, its discount rule.
|
|
1008
|
+
*/
|
|
1009
|
+
variantId?: string;
|
|
1010
|
+
/**
|
|
1011
|
+
* The site's own configuration for this line — a size, toppings, whatever it sells.
|
|
1012
|
+
*
|
|
1013
|
+
* Stored verbatim and never parsed by the server, which uses it only to tell two lines of
|
|
1014
|
+
* the same product apart. Send the SAME string for the same configuration or a second Large
|
|
1015
|
+
* opens a second line: serialize it in a stable order, or the key stops matching itself.
|
|
1016
|
+
*/
|
|
1017
|
+
variant?: string;
|
|
1018
|
+
}
|
|
1019
|
+
/** One product filling one place in a combo. */
|
|
1020
|
+
export interface ComboPick {
|
|
1021
|
+
/** `PublicComboSlot.id`. */
|
|
1022
|
+
slotId: string;
|
|
1023
|
+
/** One of that slot's `options[].productId`. */
|
|
1024
|
+
productId: string;
|
|
1025
|
+
/**
|
|
1026
|
+
* Which variant: required when the option leaves it open (`variantId: null`) and the
|
|
1027
|
+
* product has variants — one of the option's `variants[].id`.
|
|
1028
|
+
*/
|
|
1029
|
+
variantId?: string;
|
|
1030
|
+
/** The site's own configuration for the pick, as on a product line. */
|
|
1031
|
+
variant?: string;
|
|
1032
|
+
}
|
|
1033
|
+
export interface SetCartItemQuantityParams extends GetCartParams {
|
|
1034
|
+
cartItemId: string;
|
|
1035
|
+
/** Zero removes the line. */
|
|
1036
|
+
quantity: number;
|
|
1037
|
+
}
|
|
1038
|
+
export interface RemoveCartItemParams extends GetCartParams {
|
|
1039
|
+
cartItemId: string;
|
|
1040
|
+
}
|
|
1041
|
+
export interface SetCartBookingParams extends GetCartParams {
|
|
1042
|
+
/** The booking (createBooking's id) the basket is ordered for; null lets it go. */
|
|
1043
|
+
bookingId: string | null;
|
|
1044
|
+
}
|
|
1045
|
+
/**
|
|
1046
|
+
* Start paying for a basket.
|
|
1047
|
+
*
|
|
1048
|
+
* The server builds the order from the cart it holds — every line, at the quantity the
|
|
1049
|
+
* shopper chose, priced from the catalogue now — so a page cannot charge for something that
|
|
1050
|
+
* was never in the basket.
|
|
1051
|
+
*/
|
|
1052
|
+
/**
|
|
1053
|
+
* How an order reaches the customer. `delivery`: the hosted payment page asks for the address
|
|
1054
|
+
* and prices it by the shop's delivery zones.
|
|
1055
|
+
*/
|
|
1056
|
+
/** Whether an order names the location it is for - see `SiteInfo.orderLocation`. */
|
|
1057
|
+
/** Who sees the site - `getSiteInfo().customerAccess`. */
|
|
1058
|
+
export type CustomerAccess = "public" | "signed_in";
|
|
1059
|
+
export type OrderLocationMode = "never" | "optional" | "required";
|
|
1060
|
+
export type OrderType = "pickup" | "reservation" | "delivery" | "dine_in";
|
|
1061
|
+
/** A table a guest is ordering from, by the id on its QR code. */
|
|
1062
|
+
export interface PublicDiningTable {
|
|
1063
|
+
tableId: string;
|
|
1064
|
+
label: string;
|
|
1065
|
+
/** How to name it to the guest, in their language: "Table 5". */
|
|
1066
|
+
title: string;
|
|
1067
|
+
/** The restaurant it stands in - null for a shop whose plan names none. */
|
|
1068
|
+
locationId: string | null;
|
|
1069
|
+
/** The way out, in their language, for a code scanned by mistake: "Not at this table?". */
|
|
1070
|
+
leaveLabel: string;
|
|
1071
|
+
/** What to call the table code, in the page's language. */
|
|
1072
|
+
codeLabel: string;
|
|
1073
|
+
/** What to say once the code is accepted. */
|
|
1074
|
+
codeAcceptedLabel: string;
|
|
1075
|
+
/** Whether the shop takes orders from tables. */
|
|
1076
|
+
isOpen: boolean;
|
|
1077
|
+
/** What to tell the guest, in their language: to ask the staff for the table's code. */
|
|
1078
|
+
notice: string | null;
|
|
1079
|
+
}
|
|
1080
|
+
export interface CreateCheckoutParams extends GetCartParams {
|
|
1081
|
+
/**
|
|
1082
|
+
* Where the receipt goes, and who the shopper is to Stripe for saved cards. Optional: left
|
|
1083
|
+
* out, the checkout page asks for it before taking the payment — so a site needs no form.
|
|
1084
|
+
*/
|
|
1085
|
+
customerEmail?: string;
|
|
1086
|
+
/**
|
|
1087
|
+
* A phone to reach the customer about the order. Required for a delivery before it is paid:
|
|
1088
|
+
* left out, the checkout page asks for it. A signed-in customer's own phone is used otherwise.
|
|
1089
|
+
*/
|
|
1090
|
+
customerPhone?: string;
|
|
1091
|
+
/** The customer's note for the kitchen or the driver - "no onions", "ring the bell". */
|
|
1092
|
+
notes?: string;
|
|
1093
|
+
/**
|
|
1094
|
+
* Where the checkout page sends the shopper after paying. `{CHECKOUT_ID}` is replaced with
|
|
1095
|
+
* the checkout's id, so a confirmation page can look it up.
|
|
1096
|
+
*/
|
|
1097
|
+
successUrl?: string;
|
|
1098
|
+
/** Where the checkout page sends a shopper who backs out — usually the basket. */
|
|
1099
|
+
cancelUrl?: string;
|
|
1100
|
+
/**
|
|
1101
|
+
* The language the shopper is reading the shop in, as an ISO code.
|
|
1102
|
+
*
|
|
1103
|
+
* The payment page is written in it and the product names on the checkout are snapshotted in
|
|
1104
|
+
* it, so a shopper who ordered in Russian pays in Russian. Left out, the language this client
|
|
1105
|
+
* is already reading in is sent — the same one that goes out as `x-language` — which is the
|
|
1106
|
+
* right answer for every site that has a language at all. Pass it only to say something
|
|
1107
|
+
* different from what the page is rendered in.
|
|
1108
|
+
*/
|
|
1109
|
+
language?: string;
|
|
1110
|
+
/**
|
|
1111
|
+
* Where the order is picked up or served: one of the shop's active locations, from
|
|
1112
|
+
* `getLocations` - its `number` (`2`, preferred in addresses) or its `id`. Required when the site info says `orderLocation: "required"`; refused when it
|
|
1113
|
+
* names a location that is not the shop's or not on its site.
|
|
1114
|
+
*/
|
|
1115
|
+
locationId?: string | number;
|
|
1116
|
+
/**
|
|
1117
|
+
* How the order reaches the customer — one of `getSiteInfo().orderTypes`. Left out: the first
|
|
1118
|
+
* the shop offers, which the hosted payment page lets the shopper change. Refused when the
|
|
1119
|
+
* shop does not offer it.
|
|
1120
|
+
*/
|
|
1121
|
+
orderType?: OrderType;
|
|
1122
|
+
/**
|
|
1123
|
+
* When the order should be ready: a time's `at` from `getOrderTimes`. Left out, as soon as
|
|
1124
|
+
* possible. Refused when the shop does not let customers choose a time, or it is not one
|
|
1125
|
+
* offered.
|
|
1126
|
+
*/
|
|
1127
|
+
scheduledFor?: string;
|
|
1128
|
+
/**
|
|
1129
|
+
* The table booking this order is for — a guest ordering ahead for the table they booked: the
|
|
1130
|
+
* `id` `createBooking` returned, or a `bookingId` from `getCustomerBookings`. The order becomes
|
|
1131
|
+
* `reservation` at the booking's location unless `orderType` / `locationId` say otherwise, and the
|
|
1132
|
+
* shop sees it on the booking. Refused when the booking is over (finished, cancelled, no-show)
|
|
1133
|
+
* or belongs to another signed-in customer.
|
|
1134
|
+
*/
|
|
1135
|
+
bookingId?: string | number;
|
|
1136
|
+
/**
|
|
1137
|
+
* The table a guest is ordering from, by the id on its QR code. The order is then dine-in at
|
|
1138
|
+
* that table, and nothing about it can be changed; the payment page asks for the table's code.
|
|
1139
|
+
*/
|
|
1140
|
+
tableId?: string;
|
|
1141
|
+
/** That table's code, if the guest gave it already: the payment page then does not ask. */
|
|
1142
|
+
tableCode?: string;
|
|
1143
|
+
/**
|
|
1144
|
+
* False: the payment page offers no choice of when - `scheduledFor` stands, or as soon as
|
|
1145
|
+
* possible. These go in the checkout, not its address, so a guest cannot change them.
|
|
1146
|
+
*/
|
|
1147
|
+
allowTimeChoice?: boolean;
|
|
1148
|
+
/** False: no choice of how the order is received. Needs `orderType`. */
|
|
1149
|
+
allowOrderTypeChoice?: boolean;
|
|
1150
|
+
/** False: no choice of how it is paid. Needs `paymentMethod`. */
|
|
1151
|
+
allowPaymentMethodChoice?: boolean;
|
|
1152
|
+
/** How it is paid: `card` online, or `in_store`. */
|
|
1153
|
+
paymentMethod?: "card" | "in_store";
|
|
1154
|
+
/**
|
|
1155
|
+
* A promo code the customer typed, any case - money off the order after its deals, or free
|
|
1156
|
+
* delivery. Refused with the reason (`code`: `promo_code_unknown`, `promo_code_expired`,
|
|
1157
|
+
* `promo_code_used_up`, `promo_code_minimum`, ...) when it cannot go on this order. The hosted
|
|
1158
|
+
* payment page offers a code field of its own, so a site need not ask.
|
|
1159
|
+
*/
|
|
1160
|
+
promoCode?: string;
|
|
1161
|
+
/**
|
|
1162
|
+
* The signed-in customer's token, from `verifySignInCode`, `signInWithGoogle` or `signInWithApple`. The checkout
|
|
1163
|
+
* — and the order it becomes — is then theirs, and their email is used when `customerEmail`
|
|
1164
|
+
* is left out. Left out: a guest checkout, belonging to whoever the email is.
|
|
1165
|
+
*/
|
|
1166
|
+
customerToken?: string;
|
|
1167
|
+
}
|
|
1168
|
+
export type CheckoutStatus = "pending" | "paid" | "failed" | "cancelled";
|
|
1169
|
+
/** Which checkout to read, by the id `createCheckout` answered with. */
|
|
1170
|
+
export interface GetCheckoutParams {
|
|
1171
|
+
checkoutId: string;
|
|
1172
|
+
}
|
|
1173
|
+
/** Who is paying, given on the site's own payment page. */
|
|
1174
|
+
export interface SetCheckoutEmailParams extends GetCheckoutParams {
|
|
1175
|
+
email: string;
|
|
1176
|
+
}
|
|
1177
|
+
/**
|
|
1178
|
+
* What Stripe.js needs to take the card IN THE PAGE, rather than on the hosted page.
|
|
1179
|
+
*
|
|
1180
|
+
* Present only while the checkout can still be paid. None of it is a secret a shopper must be
|
|
1181
|
+
* kept from: the publishable key is public by design, and a PaymentIntent's client secret
|
|
1182
|
+
* authorises paying THIS order and nothing else — which is why Stripe's own Elements take it
|
|
1183
|
+
* in the browser. Pass it to a `"use client"` component as props; the card itself is typed
|
|
1184
|
+
* into Stripe's iframe and never touches page code.
|
|
1185
|
+
*/
|
|
1186
|
+
export interface PublicCheckoutPayment {
|
|
1187
|
+
/** The PLATFORM's publishable key. Public, and safe in a bundle. */
|
|
1188
|
+
publishableKey: string;
|
|
1189
|
+
/**
|
|
1190
|
+
* The shop's own Stripe account, when the charge is made on it.
|
|
1191
|
+
*
|
|
1192
|
+
* Stripe.js has to be loaded with it (`loadStripe(key, { stripeAccount })`) or it looks for
|
|
1193
|
+
* the PaymentIntent on the platform's account, does not find it, and the element never
|
|
1194
|
+
* mounts.
|
|
1195
|
+
*/
|
|
1196
|
+
connectedAccountId?: string;
|
|
1197
|
+
/** The PaymentIntent to confirm. */
|
|
1198
|
+
clientSecret: string;
|
|
1199
|
+
/**
|
|
1200
|
+
* Offers the cards this shopper saved at this shop, and offers to save this one.
|
|
1201
|
+
*
|
|
1202
|
+
* Only when the checkout knows who is paying — pass `customerEmail` to `createCheckout`.
|
|
1203
|
+
* Without it the payment is a one-off, which still works.
|
|
1204
|
+
*/
|
|
1205
|
+
customerSessionClientSecret?: string;
|
|
1206
|
+
/**
|
|
1207
|
+
* The card is kept for later whatever the shopper says - a booking that needs it, or a shop
|
|
1208
|
+
* that keeps every card (Sales rules → Payment methods → Online payment details). Stripe's
|
|
1209
|
+
* element then shows no "save" box: say on the page that the card is saved. Absent from an
|
|
1210
|
+
* older server: not kept.
|
|
1211
|
+
*/
|
|
1212
|
+
storesCard?: boolean;
|
|
1213
|
+
}
|
|
1214
|
+
/**
|
|
1215
|
+
* A checkout as the page TAKING the payment sees it: the order, and the secrets to charge it.
|
|
1216
|
+
*
|
|
1217
|
+
* Read with `getCheckout`. The shape differs from `createCheckout`'s answer because it answers
|
|
1218
|
+
* a different question — not "where do I send the shopper" but "what am I charging, and with
|
|
1219
|
+
* what" — so it carries the shop's name, the currency and `payment`, and no hosted URL.
|
|
1220
|
+
*/
|
|
1221
|
+
export interface PublicCheckoutSession {
|
|
1222
|
+
checkoutId: string;
|
|
1223
|
+
status: CheckoutStatus;
|
|
1224
|
+
/** The shop being paid, for the page to name in its own words. */
|
|
1225
|
+
shopName: string;
|
|
1226
|
+
/** Stripe test keys: a test card works and nothing real is charged. */
|
|
1227
|
+
testMode: boolean;
|
|
1228
|
+
/** Null until the shopper is known — no email was given at creation. */
|
|
1229
|
+
customerEmail: string | null;
|
|
1230
|
+
/** Priced by the server from the cart, so a page cannot charge its own totals. */
|
|
1231
|
+
items: {
|
|
1232
|
+
name: string;
|
|
1233
|
+
/** The variant sold, when the product has variants. */
|
|
1234
|
+
variantName?: string;
|
|
1235
|
+
quantity: number;
|
|
1236
|
+
unitPriceCents: number;
|
|
1237
|
+
}[];
|
|
1238
|
+
subtotalCents: number;
|
|
1239
|
+
totalCents: number;
|
|
1240
|
+
/** ISO 4217, lowercase. */
|
|
1241
|
+
currency: string;
|
|
1242
|
+
/** Decimal digits of every `…Cents` amount (ISO 4217): read `totalCents / 10 ** currencyMinorUnit`. */
|
|
1243
|
+
currencyMinorUnit?: number;
|
|
1244
|
+
successUrl?: string;
|
|
1245
|
+
cancelUrl?: string;
|
|
1246
|
+
/**
|
|
1247
|
+
* True: the shop takes orders from signed-in customers only and a guest made this checkout
|
|
1248
|
+
* (before the rule was on) - there is no `payment`; send them back to sign in and check out again.
|
|
1249
|
+
*/
|
|
1250
|
+
signInRequired?: boolean;
|
|
1251
|
+
/** Absent once the checkout is paid, cancelled, or otherwise no longer payable. */
|
|
1252
|
+
payment?: PublicCheckoutPayment;
|
|
1253
|
+
}
|
|
1254
|
+
export interface PublicCheckout {
|
|
1255
|
+
checkoutId: string;
|
|
1256
|
+
/**
|
|
1257
|
+
* The hosted checkout page. Send the shopper's BROWSER here — a redirect from a server
|
|
1258
|
+
* action — and the page takes the payment and returns them to `successUrl`.
|
|
1259
|
+
*/
|
|
1260
|
+
checkoutUrl: string;
|
|
1261
|
+
status: CheckoutStatus;
|
|
1262
|
+
/** Null until known — when the site left it to the checkout page, and the shopper has not got there. */
|
|
1263
|
+
customerEmail: string | null;
|
|
1264
|
+
/** In the smallest currency unit. */
|
|
1265
|
+
subtotalCents: number;
|
|
1266
|
+
totalCents: number;
|
|
1267
|
+
/** The sales tax, in the smallest unit — inside `totalCents` when `taxInclusive`. */
|
|
1268
|
+
taxCents: number;
|
|
1269
|
+
taxRate: number;
|
|
1270
|
+
taxInclusive: boolean;
|
|
1271
|
+
/** What the tax is called where the shop trades — GST, VAT, Sales tax. Label the tax line with it. */
|
|
1272
|
+
taxName: string;
|
|
1273
|
+
items: {
|
|
1274
|
+
productId?: string;
|
|
1275
|
+
productNameSnapshot: string;
|
|
1276
|
+
/** The variant sold, when the product has variants. */
|
|
1277
|
+
variantId?: string | null;
|
|
1278
|
+
/** What that variant was called, in the checkout's language. */
|
|
1279
|
+
variantName?: string | null;
|
|
1280
|
+
quantity: number;
|
|
1281
|
+
unitPriceCents: number;
|
|
1282
|
+
}[];
|
|
1283
|
+
createdAt: string;
|
|
1284
|
+
}
|
|
1285
|
+
/** A time a party can book, on the location's clock. */
|
|
1286
|
+
export interface PublicBookingSlot {
|
|
1287
|
+
/** `HH:mm` at the location. */
|
|
1288
|
+
time: string;
|
|
1289
|
+
/** The instant — what `createBooking` takes. */
|
|
1290
|
+
startsAt: string;
|
|
1291
|
+
/** Whether a table that seats the party is free for the whole visit. */
|
|
1292
|
+
available: boolean;
|
|
1293
|
+
}
|
|
1294
|
+
/** One later time an order can be for: the location's wall clock, and the instant. */
|
|
1295
|
+
export interface PublicOrderTime {
|
|
1296
|
+
/** `HH:mm` at the location. */
|
|
1297
|
+
time: string;
|
|
1298
|
+
/** The instant — what `createCheckout` takes as `scheduledFor`. */
|
|
1299
|
+
at: string;
|
|
1300
|
+
}
|
|
1301
|
+
/**
|
|
1302
|
+
* When an order can be for, on the location's own clock — the same times the hosted payment
|
|
1303
|
+
* page offers and the server accepts.
|
|
1304
|
+
*/
|
|
1305
|
+
export interface PublicOrderTimes {
|
|
1306
|
+
/** The location's zone; null when it has none — then `days` is empty. */
|
|
1307
|
+
timeZone: string | null;
|
|
1308
|
+
/** Whether "as soon as possible" can be ordered now: the location is open. */
|
|
1309
|
+
asap: boolean;
|
|
1310
|
+
/** The earliest an order can be ready (now plus the takeaway time), ISO 8601. */
|
|
1311
|
+
earliest: string;
|
|
1312
|
+
/**
|
|
1313
|
+
* Later times by day (`date` is `YYYY-MM-DD` at the location) — today only unless the shop
|
|
1314
|
+
* lets customers choose a day. Empty when the shop does not let customers choose a time.
|
|
1315
|
+
*/
|
|
1316
|
+
days: {
|
|
1317
|
+
date: string;
|
|
1318
|
+
times: PublicOrderTime[];
|
|
1319
|
+
}[];
|
|
1320
|
+
}
|
|
1321
|
+
export interface GetOrderTimesParams {
|
|
1322
|
+
/** The order's location, from `getLocations` - its `number` (`2`, preferred in addresses) or its `id`; left out, the shop's only active one. */
|
|
1323
|
+
locationId?: string | number;
|
|
1324
|
+
}
|
|
1325
|
+
/** The day's times for a party at one location. */
|
|
1326
|
+
export interface PublicBookingSlots {
|
|
1327
|
+
locationId: string;
|
|
1328
|
+
date: string;
|
|
1329
|
+
/** The clock the times are on. */
|
|
1330
|
+
timeZone: string;
|
|
1331
|
+
/** How long a booking holds its table — the length asked for, or the shop's default. */
|
|
1332
|
+
durationMinutes: number;
|
|
1333
|
+
/** The shortest reservation the shop takes, in minutes — what a guest may choose from. */
|
|
1334
|
+
minDurationMinutes?: number;
|
|
1335
|
+
/** The longest, in minutes. */
|
|
1336
|
+
maxDurationMinutes?: number;
|
|
1337
|
+
/**
|
|
1338
|
+
* The cancellation notice the guest books under: they may cancel it themselves
|
|
1339
|
+
* (`cancelBooking`) up to this many hours before it starts; 0: up to the start. Say it beside
|
|
1340
|
+
* the booking - "Free cancellation up to 2 hours before".
|
|
1341
|
+
*/
|
|
1342
|
+
cancelHours?: number;
|
|
1343
|
+
/**
|
|
1344
|
+
* False: the shop allows no free cancellation - say none; `cancelHours` promises nothing, and
|
|
1345
|
+
* cancelling costs its fee (each booking's `cancelFee`).
|
|
1346
|
+
*/
|
|
1347
|
+
freeCancellation?: boolean;
|
|
1348
|
+
/** What booking costs, in minor units of the shop's currency; 0: nothing. Paid online. */
|
|
1349
|
+
bookingFeeCents?: number;
|
|
1350
|
+
/** When it is paid: with the booking, or only for a late cancellation or a no-show. */
|
|
1351
|
+
bookingFeeCharge?: "checkout" | "on_cancel";
|
|
1352
|
+
/** Per booking, or per guest (times the party). */
|
|
1353
|
+
bookingFeePer?: "booking" | "guest";
|
|
1354
|
+
/** From how many guests the fee is asked; a smaller party pays none. */
|
|
1355
|
+
bookingFeeFromParty?: number;
|
|
1356
|
+
/**
|
|
1357
|
+
* The fee counts towards the order (a deposit): with dishes ordered for the booking it is part
|
|
1358
|
+
* of the order's price, not paid on top - say the fee only for a booking with no order.
|
|
1359
|
+
*/
|
|
1360
|
+
bookingFeeDeposit?: boolean;
|
|
1361
|
+
/** The smallest and largest party the shop takes online - a bigger one should call. */
|
|
1362
|
+
minPartySize?: number;
|
|
1363
|
+
maxPartySize?: number;
|
|
1364
|
+
/** A whole table, seats at a shared table, or a time only (no table, no plan to show). */
|
|
1365
|
+
mode: "table" | "seat" | "time";
|
|
1366
|
+
/**
|
|
1367
|
+
* What the shop reserves: `specialist` and `custom` book one of `entries`; `table` and `seat`
|
|
1368
|
+
* a table; `time` a time only.
|
|
1369
|
+
*/
|
|
1370
|
+
reservationType?: "off" | "table" | "seat" | "specialist" | "time" | "custom";
|
|
1371
|
+
/**
|
|
1372
|
+
* For a `specialist` or `custom` shop, what a guest may pick, in the shop's order - pass one
|
|
1373
|
+
* as `entryId` to see its times and to book it. Empty otherwise.
|
|
1374
|
+
*/
|
|
1375
|
+
entries?: PublicBookingEntry[];
|
|
1376
|
+
/** Rooms with bookable tables — what `seating` may name. Empty for time-only. */
|
|
1377
|
+
rooms: string[];
|
|
1378
|
+
/** Every half hour while open; empty when closed that day. */
|
|
1379
|
+
slots: PublicBookingSlot[];
|
|
1380
|
+
}
|
|
1381
|
+
/** Something a guest books by name - a specialist. */
|
|
1382
|
+
export interface PublicBookingEntry {
|
|
1383
|
+
id: string;
|
|
1384
|
+
name: string;
|
|
1385
|
+
/** Its picture, as a URL - a specialist's photo; null when it has none. */
|
|
1386
|
+
image: string | null;
|
|
1387
|
+
/**
|
|
1388
|
+
* The products it can be booked for - a dentist's treatments - while the shop books from an
|
|
1389
|
+
* allowed list (`reservationOrder: "list"`); null: anything the rules allow.
|
|
1390
|
+
*/
|
|
1391
|
+
productIds?: string[] | null;
|
|
1392
|
+
}
|
|
1393
|
+
/** What a guest books: a table, an entry of the shop's list, or a time alone. */
|
|
1394
|
+
export type ReservationKind = "table" | "list" | "time";
|
|
1395
|
+
export interface GetBookingSlotsParams {
|
|
1396
|
+
/** The location - its `number` (`2`, preferred in addresses) or its `id`. */
|
|
1397
|
+
locationId: string | number;
|
|
1398
|
+
/** `YYYY-MM-DD`. */
|
|
1399
|
+
date: string;
|
|
1400
|
+
partySize: number;
|
|
1401
|
+
/** A room from `rooms`; any when left out. */
|
|
1402
|
+
seating?: string;
|
|
1403
|
+
/** The visitor's IANA zone, for a location that keeps none. */
|
|
1404
|
+
timeZone?: string;
|
|
1405
|
+
/**
|
|
1406
|
+
* One table of the location: each time then says whether THAT table is free and seats the
|
|
1407
|
+
* party — the day of the table the guest picked. Ignored when the shop books a time only.
|
|
1408
|
+
*/
|
|
1409
|
+
tableId?: string;
|
|
1410
|
+
/** How long the visit is, in minutes — within the shop's range; its default when left out. */
|
|
1411
|
+
durationMinutes?: number;
|
|
1412
|
+
/** For a `specialist` or `custom` shop: one of `entries` - the times THAT one is free. */
|
|
1413
|
+
entryId?: string;
|
|
1414
|
+
/** Several of `entries` - the times ANY of them is free. Ignored with `entryId`. */
|
|
1415
|
+
entryIds?: string[];
|
|
1416
|
+
/**
|
|
1417
|
+
* What the visit is for - a product (a treatment). With an allowed list only the entries that
|
|
1418
|
+
* offer it count: each time says whether any of them is free.
|
|
1419
|
+
*/
|
|
1420
|
+
productId?: string;
|
|
1421
|
+
/** Several services: the times an entry that offers ALL of them is free. */
|
|
1422
|
+
productIds?: string[];
|
|
1423
|
+
/**
|
|
1424
|
+
* What is booked, of the shop's `reservationKinds` (`getSiteInfo`) - `table`, `list` (an entry
|
|
1425
|
+
* of its list: a specialist, a room), `time` alone; the shop's main way when left out.
|
|
1426
|
+
*/
|
|
1427
|
+
kind?: ReservationKind;
|
|
1428
|
+
}
|
|
1429
|
+
/** One thing drawn on the floor plan, in grid units (about a metre each). */
|
|
1430
|
+
export interface PublicPlanItem {
|
|
1431
|
+
id: string;
|
|
1432
|
+
kind: "table" | "room" | "wall" | "bar" | "door" | "window" | "plant" | "zone" | "column";
|
|
1433
|
+
label: string;
|
|
1434
|
+
shape: "round" | "rect" | null;
|
|
1435
|
+
seats: number | null;
|
|
1436
|
+
/** Chairs per side of a rectangular table. */
|
|
1437
|
+
chairs: {
|
|
1438
|
+
top: number;
|
|
1439
|
+
right: number;
|
|
1440
|
+
bottom: number;
|
|
1441
|
+
left: number;
|
|
1442
|
+
} | null;
|
|
1443
|
+
x: number;
|
|
1444
|
+
y: number;
|
|
1445
|
+
width: number;
|
|
1446
|
+
height: number;
|
|
1447
|
+
rotation: number;
|
|
1448
|
+
}
|
|
1449
|
+
/** A table's state at the asked time. */
|
|
1450
|
+
export interface PublicPlanTable {
|
|
1451
|
+
id: string;
|
|
1452
|
+
label: string;
|
|
1453
|
+
seats: number;
|
|
1454
|
+
/** The room it stands in. */
|
|
1455
|
+
room: string | null;
|
|
1456
|
+
/** Free at that time, for any party. */
|
|
1457
|
+
available: boolean;
|
|
1458
|
+
/** Free AND seats this party in the wanted room. */
|
|
1459
|
+
fits: boolean;
|
|
1460
|
+
}
|
|
1461
|
+
/** The location's floor plan at a time, with the best free table for the party. */
|
|
1462
|
+
export interface PublicBookingPlan {
|
|
1463
|
+
width: number;
|
|
1464
|
+
height: number;
|
|
1465
|
+
/** Everything to draw, rooms first. */
|
|
1466
|
+
items: PublicPlanItem[];
|
|
1467
|
+
tables: PublicPlanTable[];
|
|
1468
|
+
/** Null when none fits — and always in `time` mode, where no table is chosen. */
|
|
1469
|
+
suggestedTableId: string | null;
|
|
1470
|
+
/**
|
|
1471
|
+
* How the shop takes bookings. `time`: the plan is for looking at — no table fits, none is
|
|
1472
|
+
* suggested, and a booking that names a table or seating is refused.
|
|
1473
|
+
*/
|
|
1474
|
+
mode?: "table" | "seat" | "time";
|
|
1475
|
+
}
|
|
1476
|
+
export interface GetBookingPlanParams {
|
|
1477
|
+
/** The location - its `number` (`2`, preferred in addresses) or its `id`. */
|
|
1478
|
+
locationId: string | number;
|
|
1479
|
+
/** A slot's `startsAt`. */
|
|
1480
|
+
startsAt: string;
|
|
1481
|
+
partySize: number;
|
|
1482
|
+
seating?: string;
|
|
1483
|
+
/** How long the visit is, in minutes; the shop's default when left out. */
|
|
1484
|
+
durationMinutes?: number;
|
|
1485
|
+
/**
|
|
1486
|
+
* What is booked, of the shop's `reservationKinds` (`getSiteInfo`) - `table`, `list` (an entry
|
|
1487
|
+
* of its list: a specialist, a room), `time` alone; the shop's main way when left out.
|
|
1488
|
+
*/
|
|
1489
|
+
kind?: ReservationKind;
|
|
1490
|
+
}
|
|
1491
|
+
export interface CreateBookingParams {
|
|
1492
|
+
/** The location - its `number` (`2`, preferred in addresses) or its `id`. */
|
|
1493
|
+
locationId: string | number;
|
|
1494
|
+
/** A slot's `startsAt`. */
|
|
1495
|
+
startsAt: string;
|
|
1496
|
+
partySize: number;
|
|
1497
|
+
/**
|
|
1498
|
+
* What is booked, of the shop's `reservationKinds` (`getSiteInfo`) - `table`, `list` (an entry
|
|
1499
|
+
* of its list: a specialist, a room), `time` alone; the shop's main way when left out.
|
|
1500
|
+
*/
|
|
1501
|
+
kind?: ReservationKind;
|
|
1502
|
+
/**
|
|
1503
|
+
* Who is coming — required for a guest. With a signed-in customer (`customerToken`, or the
|
|
1504
|
+
* cookie through `@estoreclub/client`) each one left out is taken from their account.
|
|
1505
|
+
*/
|
|
1506
|
+
guestName?: string;
|
|
1507
|
+
guestPhone?: string;
|
|
1508
|
+
guestEmail?: string;
|
|
1509
|
+
/** Birthday, high chair, allergies… */
|
|
1510
|
+
notes?: string;
|
|
1511
|
+
/** The table the guest picked; the best fit when left out or taken. */
|
|
1512
|
+
tableId?: string;
|
|
1513
|
+
seating?: string;
|
|
1514
|
+
/** How long to hold the table, in minutes — within the shop's range; its default when left out. */
|
|
1515
|
+
durationMinutes?: number;
|
|
1516
|
+
/** The guest asked for a text reminder. */
|
|
1517
|
+
remind?: boolean;
|
|
1518
|
+
timeZone?: string;
|
|
1519
|
+
/** The signed-in customer's token: the booking is then theirs. */
|
|
1520
|
+
customerToken?: string;
|
|
1521
|
+
/** For a `specialist` or `custom` shop: the one to book; the first free when left out. */
|
|
1522
|
+
entryId?: string;
|
|
1523
|
+
/** Without `entryId`: the first free of these is booked. */
|
|
1524
|
+
entryIds?: string[];
|
|
1525
|
+
/**
|
|
1526
|
+
* What the visit is for - one of the shop's products, when its rules let a reservation carry
|
|
1527
|
+
* one (`reservationOrder`). With an allowed list, only an entry that offers it is booked.
|
|
1528
|
+
*/
|
|
1529
|
+
productId?: string;
|
|
1530
|
+
/**
|
|
1531
|
+
* The visit's services - the shop's products. Booked with a draft order holding them; with an
|
|
1532
|
+
* allowed list only an entry that offers ALL of them is booked.
|
|
1533
|
+
*/
|
|
1534
|
+
productIds?: string[];
|
|
1535
|
+
/** Where the payment page sends the guest back, when the shop requires payment to reserve. */
|
|
1536
|
+
successUrl?: string;
|
|
1537
|
+
cancelUrl?: string;
|
|
1538
|
+
/**
|
|
1539
|
+
* How the guest pays, where the shop offers both (`reservationPayment`): `now`, or `on_accept`
|
|
1540
|
+
* - the card held, charged when the shop accepts. Left out: the shop's way.
|
|
1541
|
+
*/
|
|
1542
|
+
payment?: ReservationPaymentTiming;
|
|
1543
|
+
}
|
|
1544
|
+
/** The ways a booking may be paid when it is made. */
|
|
1545
|
+
export interface PublicReservationPayment {
|
|
1546
|
+
/** Paid now - charged at once. */
|
|
1547
|
+
order: boolean;
|
|
1548
|
+
/** The card held now, charged when the shop accepts the booking. */
|
|
1549
|
+
deferred: boolean;
|
|
1550
|
+
}
|
|
1551
|
+
/** One booking's way of paying: charged now, or held until the shop accepts it. */
|
|
1552
|
+
export type ReservationPaymentTiming = "now" | "on_accept";
|
|
1553
|
+
/** A booking made from the site — confirmed at once. */
|
|
1554
|
+
export interface PublicBooking {
|
|
1555
|
+
id: string;
|
|
1556
|
+
/** The shop's own number for the booking (`12`) - what your links name it by; taken wherever a `bookingId` is. */
|
|
1557
|
+
bookingNumber: number | null;
|
|
1558
|
+
locationId: string;
|
|
1559
|
+
startsAt: string;
|
|
1560
|
+
partySize: number;
|
|
1561
|
+
durationMinutes: number;
|
|
1562
|
+
/** The table held for the party; null for a time-only booking. */
|
|
1563
|
+
tableLabel: string | null;
|
|
1564
|
+
room: string | null;
|
|
1565
|
+
/** The entry booked - a specialist - its name and picture; null otherwise. */
|
|
1566
|
+
entryId?: string | null;
|
|
1567
|
+
entryName?: string | null;
|
|
1568
|
+
entryImage?: string | null;
|
|
1569
|
+
/** What the visit is for - the services booked, in the order asked. */
|
|
1570
|
+
services?: {
|
|
1571
|
+
id: string;
|
|
1572
|
+
name: string;
|
|
1573
|
+
}[];
|
|
1574
|
+
/**
|
|
1575
|
+
* The draft order holding the services, paid later - at the visit, or now when the shop
|
|
1576
|
+
* requires payment to reserve (`payment`). Null when nothing was booked for.
|
|
1577
|
+
*/
|
|
1578
|
+
orderId?: string | null;
|
|
1579
|
+
orderNumber?: number | null;
|
|
1580
|
+
/** What it comes to, in major units. */
|
|
1581
|
+
orderTotal?: number | null;
|
|
1582
|
+
/**
|
|
1583
|
+
* For a `pending` booking (the shop requires payment to reserve): where the guest pays - a PATH
|
|
1584
|
+
* on the shop's own site; send them there. The time is held meanwhile and lapses unpaid.
|
|
1585
|
+
*/
|
|
1586
|
+
payment?: {
|
|
1587
|
+
checkoutId: string;
|
|
1588
|
+
checkoutUrl: string;
|
|
1589
|
+
/** `now`: charged on the payment page; `on_accept`: only held there. */
|
|
1590
|
+
timing?: ReservationPaymentTiming;
|
|
1591
|
+
} | null;
|
|
1592
|
+
/**
|
|
1593
|
+
* `confirmed`; `pending` while its payment is made; or `requested` - waiting for the shop to
|
|
1594
|
+
* accept it (its time held meanwhile). The guest is emailed the shop's answer.
|
|
1595
|
+
*/
|
|
1596
|
+
status: "confirmed" | "pending" | "requested";
|
|
1597
|
+
}
|
|
1598
|
+
/** A customer of the shop, as the site sees them. */
|
|
1599
|
+
export interface PublicCustomer {
|
|
1600
|
+
customerId: string;
|
|
1601
|
+
email: string;
|
|
1602
|
+
name: string | null;
|
|
1603
|
+
phone: string | null;
|
|
1604
|
+
/** `YYYY-MM-DD`. */
|
|
1605
|
+
dateOfBirth: string | null;
|
|
1606
|
+
/**
|
|
1607
|
+
* Their picture, as a URL — Google's profile photo, refreshed on each Google sign-in. Null:
|
|
1608
|
+
* none; draw initials. Load it with `referrerPolicy="no-referrer"`.
|
|
1609
|
+
*/
|
|
1610
|
+
avatarUrl: string | null;
|
|
1611
|
+
/**
|
|
1612
|
+
* The language they chose to read the shop in (ISO code), on any of its sites or apps - read
|
|
1613
|
+
* in it once they sign in. Null: never chosen.
|
|
1614
|
+
*/
|
|
1615
|
+
language?: string | null;
|
|
1616
|
+
/** When they first signed in. */
|
|
1617
|
+
signedUpAt: string | null;
|
|
1618
|
+
/**
|
|
1619
|
+
* Signed in and holding every detail the shop requires. False: ask for `missingFields`
|
|
1620
|
+
* (with `updateCustomerProfile`) before going on.
|
|
1621
|
+
*/
|
|
1622
|
+
onboarded: boolean;
|
|
1623
|
+
/** The required details still missing; empty once onboarded. */
|
|
1624
|
+
/**
|
|
1625
|
+
* The details still to give, then the consents the shop requires and they have not given:
|
|
1626
|
+
* `terms` (show `getTerms()`, send `acceptTerms: true`) and `healthConsent`.
|
|
1627
|
+
*/
|
|
1628
|
+
missingFields: (CustomerField | CustomerConsent)[];
|
|
1629
|
+
/**
|
|
1630
|
+
* What those missing details stop until they are given - the shop's rule: `orders` (signed
|
|
1631
|
+
* in, but ordering and booking are refused) or `sign_in` (signed out everywhere but their own
|
|
1632
|
+
* account, so a members-only site stays locked). Null once nothing is missing. Ask for the
|
|
1633
|
+
* details either way; for `sign_in` there is no skipping them.
|
|
1634
|
+
*/
|
|
1635
|
+
missingDetailsStop?: "orders" | "sign_in" | null;
|
|
1636
|
+
}
|
|
1637
|
+
/** A customer detail a shop may require, beyond the email. */
|
|
1638
|
+
export type CustomerField = "name" | "phone" | "dateOfBirth";
|
|
1639
|
+
/** A consent a shop may require, missing like a detail until it is given. */
|
|
1640
|
+
export type CustomerConsent = "terms" | "healthConsent";
|
|
1641
|
+
export type CustomerRequiredFields = Record<CustomerField, boolean>;
|
|
1642
|
+
/**
|
|
1643
|
+
* What a sign-in (or a refresh) answers with. Keep BOTH tokens where only the site's SERVER can
|
|
1644
|
+
* read them — httpOnly cookies, never browser storage — and pass `token` as `customerToken` to
|
|
1645
|
+
* the calls that take one.
|
|
1646
|
+
*/
|
|
1647
|
+
export interface PublicCustomerSession {
|
|
1648
|
+
/** Short-lived (15 minutes by default) and not revocable: what the customer's calls carry. */
|
|
1649
|
+
token: string;
|
|
1650
|
+
/**
|
|
1651
|
+
* Trades for a new `token` and a new `refreshToken` (`refreshCustomerToken`) once `token`
|
|
1652
|
+
* lapses. Single use: keep the one each refresh answers with; a spent one stops working.
|
|
1653
|
+
*/
|
|
1654
|
+
refreshToken: string;
|
|
1655
|
+
customer: PublicCustomer;
|
|
1656
|
+
}
|
|
1657
|
+
export interface RefreshCustomerTokenParams {
|
|
1658
|
+
refreshToken: string;
|
|
1659
|
+
}
|
|
1660
|
+
/** One of the signed-in customer's orders. */
|
|
1661
|
+
export interface PublicCustomerOrder {
|
|
1662
|
+
orderId: string;
|
|
1663
|
+
orderNumber: number;
|
|
1664
|
+
/** Its delivery's tracking number (`K7P-QX9-M2T`): with the order's email it opens the order on the tracking page. Null: not a delivery, or the shop does not let guests track. */
|
|
1665
|
+
trackingCode: string | null;
|
|
1666
|
+
paidAt: string;
|
|
1667
|
+
/** Minor units of `currency`. */
|
|
1668
|
+
totalCents: number;
|
|
1669
|
+
/** Refunded so far, minor units — zero for almost every order. */
|
|
1670
|
+
refundedCents: number;
|
|
1671
|
+
currency: string;
|
|
1672
|
+
/** Where it stands: being made / handed over, done, or called off. */
|
|
1673
|
+
status: "open" | "completed" | "cancelled";
|
|
1674
|
+
/** The step the shop has the order at, in the shop's own words. */
|
|
1675
|
+
state: string;
|
|
1676
|
+
orderType: string | null;
|
|
1677
|
+
locationName: string | null;
|
|
1678
|
+
/** Where a delivered order goes, with any flat or gate details; null when it is collected. */
|
|
1679
|
+
deliveryAddress?: string | null;
|
|
1680
|
+
/** How many things were ordered, quantities added up. */
|
|
1681
|
+
itemCount: number;
|
|
1682
|
+
/** The products in it, each once, first ordered first — thumbnails for a list. */
|
|
1683
|
+
productIds: string[];
|
|
1684
|
+
/** How far the shop has got; null once completed or cancelled. */
|
|
1685
|
+
progress: PublicCustomerOrderProgress | null;
|
|
1686
|
+
/** A delivered order's delivery number (`D-17`); null for any other order. */
|
|
1687
|
+
deliveryNumber?: string | null;
|
|
1688
|
+
/** Shipped by a carrier: who has it and where to follow it. Null until the shop ships it. */
|
|
1689
|
+
shipment?: PublicCustomerOrderShipment | null;
|
|
1690
|
+
/**
|
|
1691
|
+
* A delivered order's delivery: `pending`, `ready`, `picked_up` (on its way), `delivered`,
|
|
1692
|
+
* `failed` or `cancelled`; null for any other order. While it is on its way, `progress` ends
|
|
1693
|
+
* with a delivery stage.
|
|
1694
|
+
*/
|
|
1695
|
+
deliveryStatus?: "pending" | "ready" | "picked_up" | "delivered" | "failed" | "cancelled" | null;
|
|
1696
|
+
}
|
|
1697
|
+
/** A parcel handed to a carrier. */
|
|
1698
|
+
export interface PublicCustomerOrderShipment {
|
|
1699
|
+
/** Who carries it (`NZ Post`). */
|
|
1700
|
+
carrier: string;
|
|
1701
|
+
trackingNumber: string;
|
|
1702
|
+
/** The carrier's own tracking page; null when the shop gave none. */
|
|
1703
|
+
trackingUrl: string | null;
|
|
1704
|
+
shippedAt: string;
|
|
1705
|
+
}
|
|
1706
|
+
/**
|
|
1707
|
+
* Find a placed order for a tracking page: `number` - the order's (`1042`, `#1042`) or its
|
|
1708
|
+
* delivery's (`D-17`) - together with the `email` it was placed with; or `checkoutId` alone (the
|
|
1709
|
+
* confirmation link's id). Those are the credential: no customer token is involved.
|
|
1710
|
+
*/
|
|
1711
|
+
export interface TrackOrderParams {
|
|
1712
|
+
/** The delivery's tracking number (`K7P-QX9-M2T`) - with `email`. */
|
|
1713
|
+
code?: string;
|
|
1714
|
+
/** The email the order was placed with - with `code`. */
|
|
1715
|
+
email?: string;
|
|
1716
|
+
/** The confirmation link's checkout id - enough on its own. */
|
|
1717
|
+
checkoutId?: string;
|
|
1718
|
+
}
|
|
1719
|
+
/** Where an open order is in the shop's own workflow. */
|
|
1720
|
+
export interface PublicCustomerOrderProgress {
|
|
1721
|
+
/** The shop's working states, in its order — the endings ("Delivered") left out. */
|
|
1722
|
+
steps: string[];
|
|
1723
|
+
/** Index into `steps`; -1 before the shop picked it up, `steps.length` once the work is done. */
|
|
1724
|
+
current: number;
|
|
1725
|
+
}
|
|
1726
|
+
/** One line of a customer's order, as charged. Money in minor units. */
|
|
1727
|
+
export interface PublicCustomerOrderLine {
|
|
1728
|
+
/** Null on a combo line, and once the product is deleted. */
|
|
1729
|
+
productId: string | null;
|
|
1730
|
+
variantId: string | null;
|
|
1731
|
+
/** Set on a combo line. */
|
|
1732
|
+
comboId: string | null;
|
|
1733
|
+
/** The site's own configuration of the line, as the cart was sent it — to add it again. */
|
|
1734
|
+
variant: string;
|
|
1735
|
+
name: string;
|
|
1736
|
+
variantName: string | null;
|
|
1737
|
+
/** Size, extras — as the receipt says it. */
|
|
1738
|
+
detail: string;
|
|
1739
|
+
quantity: number;
|
|
1740
|
+
unitPriceCents: number;
|
|
1741
|
+
discountCents: number;
|
|
1742
|
+
/** `unitPrice × quantity − discount`. */
|
|
1743
|
+
totalCents: number;
|
|
1744
|
+
}
|
|
1745
|
+
/** One of the signed-in customer's orders, in full. */
|
|
1746
|
+
export interface PublicCustomerOrderDetail extends PublicCustomerOrder {
|
|
1747
|
+
subtotalCents: number;
|
|
1748
|
+
discountCents: number;
|
|
1749
|
+
taxCents: number;
|
|
1750
|
+
taxName: string;
|
|
1751
|
+
taxInclusive: boolean;
|
|
1752
|
+
paymentMethod: string;
|
|
1753
|
+
/** Who a delivered order is handed to, and the number the driver calls; null when collected. */
|
|
1754
|
+
recipientName?: string | null;
|
|
1755
|
+
recipientPhone?: string | null;
|
|
1756
|
+
readyBy: string | null;
|
|
1757
|
+
/**
|
|
1758
|
+
* When a delivery should be at the door - only while the shop tells its customers when a
|
|
1759
|
+
* delivery comes; null otherwise, and for an order that is not a delivery.
|
|
1760
|
+
*/
|
|
1761
|
+
deliverBy?: string | null;
|
|
1762
|
+
scheduledFor: string | null;
|
|
1763
|
+
completedAt: string | null;
|
|
1764
|
+
cancelledAt: string | null;
|
|
1765
|
+
lines: PublicCustomerOrderLine[];
|
|
1766
|
+
}
|
|
1767
|
+
/** One of the signed-in customer's bookings. */
|
|
1768
|
+
export interface PublicCustomerBooking {
|
|
1769
|
+
bookingId: string;
|
|
1770
|
+
/** The booking's own number (`12`) - what your links name it by; taken wherever a `bookingId` is. */
|
|
1771
|
+
bookingNumber: number | null;
|
|
1772
|
+
/** Its location's number (`2`). */
|
|
1773
|
+
locationNumber: number | null;
|
|
1774
|
+
startsAt: string;
|
|
1775
|
+
durationMinutes: number;
|
|
1776
|
+
partySize: number;
|
|
1777
|
+
/** waiting, confirmed, seated, finished, cancelled, no_show. */
|
|
1778
|
+
status: string;
|
|
1779
|
+
locationId: string | null;
|
|
1780
|
+
locationName: string | null;
|
|
1781
|
+
/** The tables held, by their labels; empty for a time-only booking. */
|
|
1782
|
+
tables: string[];
|
|
1783
|
+
/** The entry booked - a specialist - by name, and its picture; null otherwise. */
|
|
1784
|
+
entryName?: string | null;
|
|
1785
|
+
entryImage?: string | null;
|
|
1786
|
+
/** What the visit is for - the product (a treatment), in the shop's language. */
|
|
1787
|
+
productName?: string | null;
|
|
1788
|
+
/** What the customer typed when booking online - never the shop's own notes about them. */
|
|
1789
|
+
notes: string;
|
|
1790
|
+
/**
|
|
1791
|
+
* Until when the customer may still call it off themselves (`cancelBooking`) - the shop's
|
|
1792
|
+
* notice before the start, applied by the server; null: no longer theirs to cancel for free.
|
|
1793
|
+
*/
|
|
1794
|
+
cancellableUntil?: string | null;
|
|
1795
|
+
/**
|
|
1796
|
+
* Whether they may call it off now: free until `cancellableUntil`, and after it for
|
|
1797
|
+
* `cancelFee` where the shop charges a late-cancellation fee and the booking was paid.
|
|
1798
|
+
*/
|
|
1799
|
+
canCancel?: boolean;
|
|
1800
|
+
/**
|
|
1801
|
+
* What cancelling now costs, in the currency's smallest unit - kept from the booking's payment,
|
|
1802
|
+
* the rest refunded. Null while it is free. Say it before they confirm.
|
|
1803
|
+
*/
|
|
1804
|
+
cancelFee?: {
|
|
1805
|
+
feeCents: number;
|
|
1806
|
+
currency: string;
|
|
1807
|
+
} | null;
|
|
1808
|
+
/**
|
|
1809
|
+
* Held while it is paid for (`pending`): the shop's payment page to finish on - a path to
|
|
1810
|
+
* resolve against the page's own address, like `createBooking`'s `payment.checkoutUrl`.
|
|
1811
|
+
*/
|
|
1812
|
+
paymentUrl?: string | null;
|
|
1813
|
+
/**
|
|
1814
|
+
* The order attached to it - placed at checkout for the booking (`paid`), or its draft, paid at
|
|
1815
|
+
* the table and changeable with `setCustomerBookingPreorder` until `cancellableUntil` - or null.
|
|
1816
|
+
*/
|
|
1817
|
+
preorder?: PublicBookingPreorder | null;
|
|
1818
|
+
}
|
|
1819
|
+
/** One dish ordered ahead for a booking. Money in minor units. */
|
|
1820
|
+
export interface PublicBookingPreorderLine {
|
|
1821
|
+
/** Null once the product is deleted. */
|
|
1822
|
+
productId: string | null;
|
|
1823
|
+
name: string;
|
|
1824
|
+
quantity: number;
|
|
1825
|
+
unitPriceCents: number;
|
|
1826
|
+
/** `unitPrice × quantity − discount`. */
|
|
1827
|
+
totalCents: number;
|
|
1828
|
+
}
|
|
1829
|
+
/**
|
|
1830
|
+
* The order attached to a booking: placed at checkout for it (`createCheckout` with
|
|
1831
|
+
* `bookingId`; `paid`), or its draft - paid at the table, changeable with
|
|
1832
|
+
* `setCustomerBookingPreorder`.
|
|
1833
|
+
*/
|
|
1834
|
+
export interface PublicBookingPreorder {
|
|
1835
|
+
orderId: string;
|
|
1836
|
+
orderNumber: number;
|
|
1837
|
+
lines: PublicBookingPreorderLine[];
|
|
1838
|
+
/** Minor units of `currency`. */
|
|
1839
|
+
totalCents: number;
|
|
1840
|
+
currency: string;
|
|
1841
|
+
/** Placed and paid (online or at the counter); false: a draft, paid at the table. */
|
|
1842
|
+
paid: boolean;
|
|
1843
|
+
}
|
|
1844
|
+
/** Every dish to order ahead for a booking and how many, replacing what was there. */
|
|
1845
|
+
export interface SetBookingPreorderParams extends CustomerTokenParams {
|
|
1846
|
+
/** The booking - its `bookingNumber` (`12`) or its `bookingId`. */
|
|
1847
|
+
bookingId: string | number;
|
|
1848
|
+
/** A product of the shop, on sale, 1 to 99 of it; empty: no preorder. At most 50 lines. */
|
|
1849
|
+
lines: {
|
|
1850
|
+
productId: string;
|
|
1851
|
+
quantity: number;
|
|
1852
|
+
}[];
|
|
1853
|
+
}
|
|
1854
|
+
/** A page of a customer's history. */
|
|
1855
|
+
export interface CustomerPage<T> {
|
|
1856
|
+
data: T[];
|
|
1857
|
+
pagination: {
|
|
1858
|
+
page: number;
|
|
1859
|
+
limit: number;
|
|
1860
|
+
hasNext: boolean;
|
|
1861
|
+
};
|
|
1862
|
+
}
|
|
1863
|
+
export interface CustomerHistoryParams {
|
|
1864
|
+
page?: number;
|
|
1865
|
+
/** At most 50; 20 by default. */
|
|
1866
|
+
limit?: number;
|
|
1867
|
+
}
|
|
1868
|
+
export interface CustomerBookingsParams extends CustomerHistoryParams {
|
|
1869
|
+
/** `upcoming` (default): still ahead, soonest first. `past`: over or called off, latest first. */
|
|
1870
|
+
scope?: "upcoming" | "past" | "all";
|
|
1871
|
+
}
|
|
1872
|
+
/**
|
|
1873
|
+
* The signed-in customer, with their latest five orders and next five bookings — an account
|
|
1874
|
+
* page's first screen. The full lists: `getCustomerOrders`, `getCustomerBookings`.
|
|
1875
|
+
*/
|
|
1876
|
+
export interface PublicCustomerAccount extends PublicCustomer {
|
|
1877
|
+
orders: PublicCustomerOrder[];
|
|
1878
|
+
bookings: PublicCustomerBooking[];
|
|
1879
|
+
}
|
|
1880
|
+
export interface RequestSignInCodeParams {
|
|
1881
|
+
email: string;
|
|
1882
|
+
}
|
|
1883
|
+
export interface VerifySignInCodeParams {
|
|
1884
|
+
email: string;
|
|
1885
|
+
/** The six digits from the email. */
|
|
1886
|
+
code: string;
|
|
1887
|
+
}
|
|
1888
|
+
export interface SignInWithGoogleParams {
|
|
1889
|
+
/** The ID token (`credential`) Google Identity Services gave the page. */
|
|
1890
|
+
idToken: string;
|
|
1891
|
+
}
|
|
1892
|
+
export interface SignInWithAppleParams {
|
|
1893
|
+
/** The ID token (`credential`) the platform's Apple sign-in page posted back. */
|
|
1894
|
+
idToken: string;
|
|
1895
|
+
/**
|
|
1896
|
+
* The person's "First Last", which Apple posts beside the token on the FIRST sign-in only -
|
|
1897
|
+
* the token never carries it. Leave it out when there is none.
|
|
1898
|
+
*/
|
|
1899
|
+
name?: string | null;
|
|
1900
|
+
}
|
|
1901
|
+
export interface CustomerTokenParams {
|
|
1902
|
+
/** The token from `verifySignInCode`, `signInWithGoogle` or `signInWithApple`. */
|
|
1903
|
+
customerToken: string;
|
|
1904
|
+
}
|
|
1905
|
+
/**
|
|
1906
|
+
* A place the signed-in customer has had an order delivered to, or saved themselves. One per
|
|
1907
|
+
* address and details: the same one again only moves `lastUsedAt`.
|
|
1908
|
+
*/
|
|
1909
|
+
export interface PublicCustomerAddress {
|
|
1910
|
+
customerAddressId: string;
|
|
1911
|
+
/** The address as it was picked - one line. */
|
|
1912
|
+
address: string;
|
|
1913
|
+
/** Flat, floor, gate code - whatever the driver needs on top of the address. */
|
|
1914
|
+
details: string | null;
|
|
1915
|
+
/** Where it is; null for an address kept without a point. */
|
|
1916
|
+
latitude: number | null;
|
|
1917
|
+
longitude: number | null;
|
|
1918
|
+
postcode: string | null;
|
|
1919
|
+
/** ISO 8601. The list is ordered by it, the one used last first. */
|
|
1920
|
+
lastUsedAt: string;
|
|
1921
|
+
}
|
|
1922
|
+
/**
|
|
1923
|
+
* A card the signed-in customer saved paying at this shop: what it is and when it expires.
|
|
1924
|
+
* Nothing in it can pay - the card stays with Stripe, and `id` is only a handle for removing it.
|
|
1925
|
+
*/
|
|
1926
|
+
export interface PublicCustomerPaymentMethod {
|
|
1927
|
+
/** A handle for `deleteCustomerPaymentMethod` - not Stripe's id, and of no use to pay with. */
|
|
1928
|
+
id: string;
|
|
1929
|
+
/** Stripe's card brand: `visa`, `mastercard`, `amex`... */
|
|
1930
|
+
brand: string;
|
|
1931
|
+
last4: string;
|
|
1932
|
+
expMonth: number;
|
|
1933
|
+
expYear: number;
|
|
1934
|
+
/** The wallet it was added from (`apple_pay`, `google_pay`), if any. */
|
|
1935
|
+
wallet: string | null;
|
|
1936
|
+
/** An upcoming booking keeps it (a late-cancellation fee): it cannot be removed until then. */
|
|
1937
|
+
inUse: boolean;
|
|
1938
|
+
}
|
|
1939
|
+
/** An address to save, as a checkout gives one: the address, and its point when known. */
|
|
1940
|
+
export interface AddCustomerAddressParams extends CustomerTokenParams {
|
|
1941
|
+
address: string;
|
|
1942
|
+
details?: string | null;
|
|
1943
|
+
latitude?: number | null;
|
|
1944
|
+
longitude?: number | null;
|
|
1945
|
+
postcode?: string | null;
|
|
1946
|
+
}
|
|
1947
|
+
export interface UpdateCustomerProfileParams extends CustomerTokenParams {
|
|
1948
|
+
name?: string | null;
|
|
1949
|
+
phone?: string | null;
|
|
1950
|
+
/** `YYYY-MM-DD`, in the past. */
|
|
1951
|
+
dateOfBirth?: string | null;
|
|
1952
|
+
/**
|
|
1953
|
+
* True: the customer accepts the shop's terms (`getTerms()`) - kept with its time, from the
|
|
1954
|
+
* first time. Only ever from a box they ticked themselves.
|
|
1955
|
+
*/
|
|
1956
|
+
acceptTerms?: boolean;
|
|
1957
|
+
/** True: they consent to the shop keeping health information; false: withdrawn. */
|
|
1958
|
+
healthConsent?: boolean;
|
|
1959
|
+
/**
|
|
1960
|
+
* The language they just chose to read the shop in, an ISO code - kept on their account and
|
|
1961
|
+
* answered as `PublicCustomer.language` wherever they sign in. Null forgets it.
|
|
1962
|
+
*/
|
|
1963
|
+
language?: string | null;
|
|
1964
|
+
}
|
|
1965
|
+
/** Money off for paying one way: an amount in MINOR units of the shop's currency, or a percent. */
|
|
1966
|
+
export interface PublicPaymentDiscount {
|
|
1967
|
+
kind: "amount" | "percent";
|
|
1968
|
+
value: number;
|
|
1969
|
+
}
|
|
1970
|
+
/** The discount for each way of paying, or null for none. */
|
|
1971
|
+
export interface PublicPaymentDiscounts {
|
|
1972
|
+
online: PublicPaymentDiscount | null;
|
|
1973
|
+
inStore: PublicPaymentDiscount | null;
|
|
1974
|
+
}
|
|
1975
|
+
/**
|
|
1976
|
+
* How customers vote, as the shop set it (Sales rules → Social): not at all, a like only (`up` -
|
|
1977
|
+
* no dislikes; its votes read as `like`, with `dislikes` 0), a like or a dislike, or stars.
|
|
1978
|
+
*/
|
|
1979
|
+
export type ProductVoting = "off" | "up" | "like" | "range";
|
|
1980
|
+
/**
|
|
1981
|
+
* The votes on a product, the shop's way: stars (`range` - `average` of up to `max`) or likes
|
|
1982
|
+
* (`likes` and `dislikes`), and the viewer's own.
|
|
1983
|
+
*/
|
|
1984
|
+
export interface PublicProductRating {
|
|
1985
|
+
method: "like" | "range";
|
|
1986
|
+
/** Average stars, to one decimal; null before anyone rated. */
|
|
1987
|
+
average: number | null;
|
|
1988
|
+
/** Customers who voted on it. */
|
|
1989
|
+
count: number;
|
|
1990
|
+
/** The top of the scale - 1 for likes. */
|
|
1991
|
+
max: number;
|
|
1992
|
+
likes: number;
|
|
1993
|
+
dislikes: number;
|
|
1994
|
+
/** The signed-in customer's own vote - stars, or 1 / -1; null when none. */
|
|
1995
|
+
mine: number | null;
|
|
1996
|
+
}
|
|
1997
|
+
/**
|
|
1998
|
+
* What a product takes - comments, stars, likes on comments - and what has been said. The
|
|
1999
|
+
* shop turns each on in its product settings; a product that takes none answers all `false`.
|
|
2000
|
+
*/
|
|
2001
|
+
export interface PublicProductFeedback {
|
|
2002
|
+
allowComments: boolean;
|
|
2003
|
+
allowRating: boolean;
|
|
2004
|
+
allowCommentVotes: boolean;
|
|
2005
|
+
/** How customers vote on this product - `off` when they don't. */
|
|
2006
|
+
productVoting: ProductVoting;
|
|
2007
|
+
/** How customers vote on its comments - `off` when they don't (always, without comments). */
|
|
2008
|
+
commentVoting: ProductVoting;
|
|
2009
|
+
/** How many stars a comment is rated out of, while `commentVoting` is `range`. */
|
|
2010
|
+
commentStars: number;
|
|
2011
|
+
/** Comments and replies, together. */
|
|
2012
|
+
commentCount: number;
|
|
2013
|
+
rating: PublicProductRating;
|
|
2014
|
+
/**
|
|
2015
|
+
* A vote comes with a comment (Sales rules → Social): `rateProduct` is refused
|
|
2016
|
+
* (`vote_needs_comment`) until the customer has a comment of their own on the product - cast
|
|
2017
|
+
* it with the comment instead (`createProductComment`'s `vote`). Deleting their last comment
|
|
2018
|
+
* takes their vote back. Only while comments and product votes are both on.
|
|
2019
|
+
*/
|
|
2020
|
+
voteNeedsComment: boolean;
|
|
2021
|
+
}
|
|
2022
|
+
/** One comment on a product, or a reply to one. Threads are one level deep. */
|
|
2023
|
+
export interface PublicProductComment {
|
|
2024
|
+
id: string;
|
|
2025
|
+
/** The root it replies to, or null for a root. */
|
|
2026
|
+
parentId: string | null;
|
|
2027
|
+
body: string;
|
|
2028
|
+
/** ISO timestamp. */
|
|
2029
|
+
createdAt: string;
|
|
2030
|
+
/** Replies under this root (0 on a reply). */
|
|
2031
|
+
replyCount: number;
|
|
2032
|
+
likes: number;
|
|
2033
|
+
dislikes: number;
|
|
2034
|
+
/** Average stars, while comments are voted on with stars; null before anyone rated. */
|
|
2035
|
+
ratingAverage: number | null;
|
|
2036
|
+
ratingCount: number;
|
|
2037
|
+
/**
|
|
2038
|
+
* Who wrote it. `fromShop`: the shop's own reply, written in its admin - `name` is then the
|
|
2039
|
+
* shop's name; mark it as the shop's.
|
|
2040
|
+
*/
|
|
2041
|
+
author: {
|
|
2042
|
+
name: string | null;
|
|
2043
|
+
avatarUrl: string | null;
|
|
2044
|
+
fromShop: boolean;
|
|
2045
|
+
};
|
|
2046
|
+
/** The signed-in customer's vote on it: 1 / -1, or stars; 0 for none. */
|
|
2047
|
+
myVote: number;
|
|
2048
|
+
/**
|
|
2049
|
+
* The author's own vote on the product - stars, or 1 / -1 - for a review's stars or thumb
|
|
2050
|
+
* beside the name. Null when they cast none, and always on a reply.
|
|
2051
|
+
*/
|
|
2052
|
+
authorVote: number | null;
|
|
2053
|
+
/** Written by the signed-in customer - they may delete it. */
|
|
2054
|
+
mine: boolean;
|
|
2055
|
+
}
|
|
2056
|
+
/** A page of comments. `total` counts every comment the page is a slice of. */
|
|
2057
|
+
export interface PublicProductCommentsPage {
|
|
2058
|
+
data: PublicProductComment[];
|
|
2059
|
+
pagination: {
|
|
2060
|
+
page: number;
|
|
2061
|
+
limit: number;
|
|
2062
|
+
hasNext: boolean;
|
|
2063
|
+
};
|
|
2064
|
+
total: number;
|
|
2065
|
+
}
|
|
2066
|
+
export interface GetProductFeedbackParams {
|
|
2067
|
+
productId: string;
|
|
2068
|
+
/** A signed-in customer, for their own stars. */
|
|
2069
|
+
customerToken?: string;
|
|
2070
|
+
}
|
|
2071
|
+
export interface GetProductCommentsParams {
|
|
2072
|
+
productId: string;
|
|
2073
|
+
/** A root comment: its replies, oldest first. Without it, the roots, newest first. */
|
|
2074
|
+
parentId?: string;
|
|
2075
|
+
page?: number;
|
|
2076
|
+
/** Up to 50; 20 by default. */
|
|
2077
|
+
limit?: number;
|
|
2078
|
+
/** A signed-in customer, for `mine` and `myVote`. */
|
|
2079
|
+
customerToken?: string;
|
|
2080
|
+
}
|
|
2081
|
+
export interface CreateProductCommentParams extends CustomerTokenParams {
|
|
2082
|
+
productId: string;
|
|
2083
|
+
/** Up to 2000 characters. */
|
|
2084
|
+
body: string;
|
|
2085
|
+
/** The comment this replies to - a reply to a reply is filed under the same root. */
|
|
2086
|
+
parentId?: string;
|
|
2087
|
+
/**
|
|
2088
|
+
* The customer's vote on the product, cast with the comment (a review) - the shop's way, as
|
|
2089
|
+
* `RateProductParams.value`. A root comment only; required in practice while
|
|
2090
|
+
* `voteNeedsComment` is on, as `rateProduct` alone is refused then.
|
|
2091
|
+
*/
|
|
2092
|
+
vote?: number;
|
|
2093
|
+
}
|
|
2094
|
+
/** A comment's votes after one was cast. */
|
|
2095
|
+
export interface PublicCommentVoteResult {
|
|
2096
|
+
likes: number;
|
|
2097
|
+
dislikes: number;
|
|
2098
|
+
ratingAverage: number | null;
|
|
2099
|
+
ratingCount: number;
|
|
2100
|
+
myVote: number;
|
|
2101
|
+
}
|
|
2102
|
+
export interface RateProductParams extends CustomerTokenParams {
|
|
2103
|
+
productId: string;
|
|
2104
|
+
/**
|
|
2105
|
+
* The shop's way (`productVoting`): 1 to `rating.max` stars, or 1 like / -1 dislike - a like
|
|
2106
|
+
* (1) only, under `up`.
|
|
2107
|
+
*/
|
|
2108
|
+
value: number;
|
|
2109
|
+
}
|
|
2110
|
+
export interface UnrateProductParams extends CustomerTokenParams {
|
|
2111
|
+
productId: string;
|
|
2112
|
+
}
|
|
2113
|
+
export interface VoteProductCommentParams extends CustomerTokenParams {
|
|
2114
|
+
productId: string;
|
|
2115
|
+
commentId: string;
|
|
2116
|
+
/** The shop's way (`commentVoting`): 1 / -1, or 1 to `commentStars`; 0 takes it back. */
|
|
2117
|
+
value: number;
|
|
2118
|
+
}
|
|
2119
|
+
export interface DeleteProductCommentParams extends CustomerTokenParams {
|
|
2120
|
+
productId: string;
|
|
2121
|
+
/** One of the customer's own comments. A root goes with its replies. */
|
|
2122
|
+
commentId: string;
|
|
2123
|
+
}
|