@wix/agent-skills 1.9.0 → 1.11.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/package.json +4 -1
- package/skills/wix-headless/references/DESIGN_SYSTEM.md +6 -16
- package/skills/wix-headless/references/astro/bookings/COMPONENTS.md +1 -1
- package/skills/wix-headless/references/astro/bookings/SERVICES_PAGES.md +19 -0
- package/skills/wix-headless/references/astro/cms/FAQ_KNOWLEDGE_BASE.md +2 -2
- package/skills/wix-headless/references/astro/designer/INSTRUCTIONS.md +3 -3
- package/skills/wix-headless/references/astro/ecom/CART_WIRING.md +2 -2
- package/skills/wix-headless/references/astro/ecom/COMPONENTS_CSS.md +3 -3
- package/skills/wix-headless/references/astro/gift-cards/COMPONENTS.md +2 -2
- package/skills/wix-headless/references/astro/stores/BACK_IN_STOCK.md +7 -7
- package/skills/wix-headless/references/astro/stores/COMPONENTS_CSS.md +4 -4
- package/skills/wix-headless/references/astro/stores/PRODUCT_PAGES.md +2 -2
- package/skills/wix-headless/references/astro/templates/Footer.astro +4 -4
- package/skills/wix-headless/references/astro/templates/Navigation.astro +4 -4
- package/skills/wix-headless/references/astro/templates/bookings/AvailabilityCalendar.tsx +147 -6
- package/skills/wix-headless/references/astro/templates/bookings/ServiceBookingFlow.tsx +21 -4
- package/skills/wix-headless/references/astro/templates/bookings/ServiceCard.astro +11 -2
- package/skills/wix-headless/references/astro/templates/bookings/booking-confirmation.astro +8 -8
- package/skills/wix-headless/references/astro/templates/bookings/components-bookings.css +94 -26
- package/skills/wix-headless/references/astro/templates/bookings/services/[slug].astro +53 -10
- package/skills/wix-headless/references/astro/templates/bookings/services/index.astro +128 -20
- package/skills/wix-headless/references/astro/templates/ecom/CartView.tsx +3 -3
- package/skills/wix-headless/references/astro/templates/ecom/cart.astro +3 -3
- package/skills/wix-headless/references/astro/templates/ecom/components-ecom.css +17 -17
- package/skills/wix-headless/references/astro/templates/ecom/thank-you.astro +3 -3
- package/skills/wix-headless/references/astro/templates/gift-cards/_home-teaser-snippet.astro +4 -4
- package/skills/wix-headless/references/astro/templates/gift-cards/components-gift-cards.css +19 -18
- package/skills/wix-headless/references/astro/templates/gift-cards/gift-cards.astro +3 -3
- package/skills/wix-headless/references/astro/templates/global.css +17 -15
- package/skills/wix-headless/references/astro/templates/index.astro +4 -4
- package/skills/wix-headless/references/astro/templates/stores/components-stores.css +31 -31
- package/skills/wix-headless/references/astro/templates/stores/products/[slug].astro +4 -4
- package/skills/wix-headless/references/bookings/FLOW.md +93 -32
- package/skills/wix-headless/references/bookings/INSTRUCTIONS.md +8 -3
- package/skills/wix-headless/references/bookings/SERVICES_DATA.md +60 -0
- package/skills/wix-headless/references/custom/bookings/WIRING.md +60 -9
- package/skills/wix-headless/references/shared/DESIGN_MD.md +2 -3
- package/skills/wix-headless/references/shared/IMPLEMENTER.md +4 -4
- package/skills/wix-headless/references/shared/STYLING.md +15 -18
- package/skills/wix-headless/references/stores/INSTRUCTIONS.md +2 -2
- package/skills/wix-headless/references/verticals/bookings.md +5 -3
- package/skills/wix-headless/scripts/compose.mjs +4 -19
- package/skills/wix-headless/scripts/emit-design-tokens.mjs +0 -3
- package/skills/wix-manage/references/bookings/create-appointment-service.md +3 -28
- package/skills/wix-manage/references/bookings/create-booking-service-from-prompt.md +1 -8
- package/skills/wix-manage/references/bookings/create-class-service.md +3 -28
- package/skills/wix-manage/references/bookings/create-course-service.md +3 -28
|
@@ -32,16 +32,17 @@ Client-side `@wix/sdk` — CDN imports for `none`-build, bundled for `own`-build
|
|
|
32
32
|
## The client (acquire once)
|
|
33
33
|
```js
|
|
34
34
|
import { createClient, OAuthStrategy } from "https://esm.sh/@wix/sdk@1"; // bundled for own-build
|
|
35
|
-
import { services, availabilityTimeSlots, eventTimeSlots, bookings } from "https://esm.sh/@wix/bookings@1";
|
|
35
|
+
import { services, availabilityTimeSlots, eventTimeSlots, bookings, categoriesV2 } from "https://esm.sh/@wix/bookings@1";
|
|
36
36
|
import { forms } from "https://esm.sh/@wix/forms@1";
|
|
37
37
|
import * as cartV2 from "https://esm.sh/@wix/auto_sdk_ecom_cart-v-2@1";
|
|
38
38
|
import { redirects } from "https://esm.sh/@wix/redirects@1";
|
|
39
39
|
|
|
40
40
|
const wix = createClient({
|
|
41
|
-
modules: { services, availabilityTimeSlots, eventTimeSlots, bookings, forms, redirects, ...cartV2 },
|
|
41
|
+
modules: { services, availabilityTimeSlots, eventTimeSlots, bookings, categoriesV2, forms, redirects, ...cartV2 },
|
|
42
42
|
auth: OAuthStrategy({ clientId: "REPLACE_WITH_APP_ID" }),
|
|
43
43
|
});
|
|
44
44
|
```
|
|
45
|
+
(`categoriesV2` + `services.queryLocations` power the optional catalog filters; drop them if you don't surface filters.)
|
|
45
46
|
|
|
46
47
|
## Render services
|
|
47
48
|
```js
|
|
@@ -54,21 +55,68 @@ const { items } = await wix.services.queryServices({
|
|
|
54
55
|
const visible = items.filter((s) => !s.hidden);
|
|
55
56
|
// name s.name · tagline s.tagLine · slug s.mainSlug?.name ·
|
|
56
57
|
// duration s.schedule?.availabilityConstraints?.sessionDurations?.[0] ·
|
|
57
|
-
// price s.payment?.fixed?.price ({ value, currency } — value is a string)
|
|
58
|
+
// price s.payment?.fixed?.price ({ value, currency } — value is a string) ·
|
|
59
|
+
// staff s.staffMemberDetails?.staffMembers ([{ staffMemberId, name }] — staffMemberId IS the resource id).
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Optional catalog filters — location & category
|
|
63
|
+
Both auto-skip when there's nothing to choose (see `../../bookings/FLOW.md` §7).
|
|
64
|
+
Merge the chosen filter into the **same** `queryServices` filter and re-query.
|
|
65
|
+
```js
|
|
66
|
+
// Locations — show the selector only when count > 1.
|
|
67
|
+
const loc = await wix.services.queryLocations();
|
|
68
|
+
const businessLocations = loc.businessLocations?.locations ?? []; // [{ _id, type, business: { name } }]
|
|
69
|
+
const count = businessLocations.length + (loc.customLocations?.exists ? 1 : 0) + (loc.customerLocations?.exists ? 1 : 0);
|
|
70
|
+
// Categories — non-fatal; show the bar only when > 1.
|
|
71
|
+
const cats = (await wix.categoriesV2.queryCategories().find()).items ?? []; // [{ _id, name }]
|
|
72
|
+
|
|
73
|
+
// Merge into the services filter:
|
|
74
|
+
const filter = { appId: BOOKING_APP_ID };
|
|
75
|
+
if (categoryId) filter["category.id"] = { $eq: categoryId };
|
|
76
|
+
if (locationId === "custom") filter["locations.type"] = { $hasSome: ["CUSTOM"] };
|
|
77
|
+
else if (locationId === "customer") filter["locations.type"] = { $hasSome: ["CUSTOMER"] };
|
|
78
|
+
else if (locationId) filter["locations.business.id"] = { $hasSome: [locationId] };
|
|
79
|
+
// → wix.services.queryServices({ query: { filter, paging: { limit: 100 } }, conditionalFields: ["STAFF_MEMBER_DETAILS"] }).find()
|
|
80
|
+
// Carry locationId/locationType into the availability call so slots are scoped to it.
|
|
58
81
|
```
|
|
59
82
|
|
|
60
83
|
## Availability (week calendar)
|
|
61
84
|
Render a **week calendar** (day strip → the day's times), not a flat grid — see
|
|
62
85
|
`../../bookings/FLOW.md` § 5. `fromLocalDate`/`toLocalDate` are **local** strings
|
|
63
86
|
(`YYYY-MM-DDThh:mm:ss`, no `Z`) + a `timeZone`.
|
|
87
|
+
|
|
88
|
+
> **Multi-location: scope to ONE business location.** Unscoped,
|
|
89
|
+
> `listAvailabilityTimeSlots` returns **one slot per location** per time → duplicate
|
|
90
|
+
> rows. Source the location list from **`queryLocations()`** (the site's real business
|
|
91
|
+
> locations, whose ids the availability engine recognizes) intersected with the
|
|
92
|
+
> service's own location ids — NOT from `service.locations` alone (its entries can
|
|
93
|
+
> carry an id the engine doesn't recognize → scoping returns 0 slots). Default to the
|
|
94
|
+
> carried/first and pass the single-location filter below; with no business locations,
|
|
95
|
+
> leave it unscoped. (Staff does NOT multiply rows — only location does.) See FLOW.md §7.
|
|
64
96
|
```js
|
|
65
|
-
// APPOINTMENT — serviceId is a single GUID STRING:
|
|
66
|
-
const a = await wix.availabilityTimeSlots.listAvailabilityTimeSlots({
|
|
97
|
+
// APPOINTMENT — serviceId is a single GUID STRING. Staff (§8) OPTIONAL; location ALWAYS when >1:
|
|
98
|
+
const a = await wix.availabilityTimeSlots.listAvailabilityTimeSlots({
|
|
99
|
+
serviceId, fromLocalDate, toLocalDate, timeZone, bookable: true, cursorPaging: { limit: 100 },
|
|
100
|
+
// staff: resourceTypes: [{ resourceTypeId: STAFF_MEMBER_RESOURCE_TYPE_ID, resourceIds: [resourceId] }], includeResourceTypeIds: [STAFF_MEMBER_RESOURCE_TYPE_ID],
|
|
101
|
+
// location: locations: [{ _id: locationId, locationType: "BUSINESS" }],
|
|
102
|
+
});
|
|
67
103
|
// slots a.timeSlots[] — localStartDate/localEndDate/scheduleId at the TOP level.
|
|
68
|
-
// CLASS — different namespace, PLURAL serviceIds; slots carry eventInfo.eventId, no scheduleId
|
|
69
|
-
|
|
104
|
+
// CLASS — different namespace, PLURAL serviceIds; slots carry eventInfo.eventId, no scheduleId.
|
|
105
|
+
// CLASS filters staff + location via eventFilter:
|
|
106
|
+
const c = await wix.eventTimeSlots.listEventTimeSlots({
|
|
107
|
+
serviceIds: [serviceId], fromLocalDate, toLocalDate, timeZone, includeNonBookable: false,
|
|
108
|
+
// eventFilter: { "resources.id": { $hasSome: [resourceId] }, "location.id": [locationId] },
|
|
109
|
+
});
|
|
70
110
|
```
|
|
71
111
|
|
|
112
|
+
## Optional staff selection
|
|
113
|
+
The staff list is on the service (`s.staffMemberDetails.staffMembers` → `[{ staffMemberId, name }]`;
|
|
114
|
+
`staffMemberId` IS the resource id despite the name). Show a picker only when >1 staff.
|
|
115
|
+
Filtering uses that `staffMemberId` (the `resourceId`/`resourceIds` above).
|
|
116
|
+
When a specific staff is chosen, set `slot.resource = { _id: staffMemberId, name }` on the
|
|
117
|
+
slot you pass to `createBooking` (the booking books that resource); leave it unset for
|
|
118
|
+
"any staff" → the **ANY_RESOURCE fallback** already in the booking snippet below.
|
|
119
|
+
|
|
72
120
|
## Booking form — schema-driven
|
|
73
121
|
The booking form is a `@wix/forms` form on the service (`service.form._id`). Read
|
|
74
122
|
its schema and render fields by `componentType`, collecting values keyed by
|
|
@@ -95,6 +143,8 @@ const STAFF_MEMBER_RESOURCE_TYPE_ID = "1cd44cf8-756f-41c3-bd90-3e2ffcaf1155";
|
|
|
95
143
|
|
|
96
144
|
// Build the slot. APPOINTMENT carries scheduleId; CLASS carries eventId (Wix
|
|
97
145
|
// derives the rest). No staff chosen → the ANY_RESOURCE fallback.
|
|
146
|
+
// When a specific staff was chosen, use `resource: { _id: resourceId, name }`
|
|
147
|
+
// INSTEAD of `resourceSelections` (drop the ANY_RESOURCE fallback for that slot).
|
|
98
148
|
const slot =
|
|
99
149
|
slotType === "CLASS"
|
|
100
150
|
? { serviceId, eventId, timezone }
|
|
@@ -140,7 +190,8 @@ if (checkoutRequired) {
|
|
|
140
190
|
> Confirm the `@wix/auto_sdk_ecom_cart-v-2` function registration shape on a
|
|
141
191
|
> CDN/own client at wiring time; the payloads above match the astro `bookingDriver.ts`.
|
|
142
192
|
|
|
143
|
-
## Out of
|
|
144
|
-
Waitlist and on-site manage/cancel — out of scope (same as the astro vertical
|
|
193
|
+
## Out of scope
|
|
194
|
+
Waitlist and on-site manage/cancel — out of scope (same as the astro vertical;
|
|
195
|
+
neither has a headless SoT — display-only policy flags only, no join/cancel logic).
|
|
145
196
|
Show bookable slots only; post-booking self-service is handled by the Wix-hosted
|
|
146
197
|
flow / member area.
|
|
@@ -21,8 +21,6 @@ typography:
|
|
|
21
21
|
fontWeight: <number> # optional
|
|
22
22
|
lineHeight: <Dimension|number> # optional
|
|
23
23
|
letterSpacing: <Dimension> # optional
|
|
24
|
-
spacing:
|
|
25
|
-
<scale-level>: <Dimension|number>
|
|
26
24
|
rounded: # corner radii (DESIGN.md's name for radius tokens)
|
|
27
25
|
<scale-level>: <Dimension>
|
|
28
26
|
containers: # EXTENSION (this skill): content/reading widths
|
|
@@ -51,11 +49,12 @@ googleFontsHref: <string> # EXTENSION (this skill): the ready Google Fonts <li
|
|
|
51
49
|
|---|---|---|
|
|
52
50
|
| `colors` | `--color-<key>` | semantic role keys (see color roles below) |
|
|
53
51
|
| `typography.<level>.fontFamily` | `--font-<level>` | `display` + `body` required; `mono` optional |
|
|
54
|
-
| `spacing` | `--spacing-<key>` | full `2xs…4xl` rhythm scale |
|
|
55
52
|
| `rounded` | `--radius-<key>` | `sm` + `md` required |
|
|
56
53
|
| `containers` | `--container-<key>` | **extension** — content widths, a separate axis from spacing (`prose, md, 3xl, 6xl`) |
|
|
57
54
|
| `googleFontsHref` | the Layout `<link>` href | **extension** — the ready stylesheet URL for the chosen families |
|
|
58
55
|
|
|
56
|
+
> **Spacing is not a DESIGN.md token.** The build uses Tailwind v4's built-in numeric spacing scale directly (`gap-4`, `py-24`, `px-6`, …). A named `--spacing-<size>` scale was removed because its t-shirt names (`md`, `3xl`, …) collided with the width utilities (`max-w-3xl` resolved to `--spacing-3xl` instead of `--container-3xl`). Do not author a `spacing` group.
|
|
57
|
+
|
|
59
58
|
### Color roles — wix-native keys are the contract
|
|
60
59
|
|
|
61
60
|
The skill's component-CSS templates reference a fixed set of `--color-*` names (`STYLING.md` § "Required tokens"). So the **canonical color token keys in our DESIGN.md are the wix editorial roles** — and these are valid DESIGN.md color token names (the format leaves token names free-form):
|
|
@@ -41,7 +41,7 @@ Every input you need is either inlined in your prompt or — for seeded entity I
|
|
|
41
41
|
| Scope | Where its inputs come from |
|
|
42
42
|
|---|---|
|
|
43
43
|
| `seed` | All **inlined**: `brand`, `intent.<pack>`, `siteId`, recipe path(s). Do NOT re-derive these. |
|
|
44
|
-
| `components` | **Inlined**: `brand`. **Read from disk**: the design tokens (the DESIGN.md vocabulary — `colors`/`typography`/`
|
|
44
|
+
| `components` | **Inlined**: `brand`. **Read from disk**: the design tokens (the DESIGN.md vocabulary — `colors`/`typography`/`rounded`/`containers`; spacing is Tailwind's numeric scale, not a token) from `.wix/design-tokens.css` (gate-verified present; also the CSS variables the build consumes). Components do not need seeded IDs. |
|
|
45
45
|
| `pages` / `pages-*` | **Inlined:** `brand`. **Read from disk:** the design tokens (`.wix/design-tokens.css`, DESIGN.md vocabulary); your `seeded.<vertical>` slice from `.wix/seeded.json` (products, posts, collections IDs). Page data wiring uses live SDK queries; the `seeded` data is for path resolution + demo content authoring. |
|
|
46
46
|
|
|
47
47
|
If a required **inlined** input is missing from your prompt, or your **`.wix/seeded.json` slice** is absent (e.g. you are dispatched as `pages-products` but `.wix/seeded.json` has no `seeded.stores`), fail fast — return `status: "failed"` with `errors: [{ code: "SEEDED_JSON_SLICE_MISSING", missing: "seeded.stores.products" }]` (or `PROMPT_INCOMPLETE` for an inlined gap). Do NOT re-fetch via curl — the gap means an upstream phase didn't complete, and re-querying would mask the real bug.
|
|
@@ -120,11 +120,11 @@ The full styling contract (tokens-as-utilities default, when global semantic cla
|
|
|
120
120
|
|
|
121
121
|
- **camelCase for identifiers, kebab-case for filenames, PascalCase for components.** Example: `ProductCard.astro`, `queryBlogPosts` function, `cart-updated` event.
|
|
122
122
|
- **No inline styles beyond design-token CSS variables.** `style={{ color: "red" }}` is forbidden; `style={{ color: "var(--color-accent)" }}` is fine.
|
|
123
|
-
- **Tailwind v4 `@reference` is mandatory in any scoped CSS that uses `@apply`.** Tailwind v4 isolates `@apply` per file — utilities defined in the main entry CSS (where `@theme` lives) are NOT visible to `components-*.css` unless that file prepends `@reference "./global.css";` on line 1. If your scope writes a `components-<vertical>.css` that uses `@apply` with theme tokens (e.g., `@apply gap-
|
|
123
|
+
- **Tailwind v4 `@reference` is mandatory in any scoped CSS that uses `@apply`.** Tailwind v4 isolates `@apply` per file — utilities defined in the main entry CSS (where `@theme` lives) are NOT visible to `components-*.css` unless that file prepends `@reference "./global.css";` on line 1. If your scope writes a `components-<vertical>.css` that uses `@apply` with theme tokens (e.g., `@apply gap-3 font-display text-sm`), the file MUST start with:
|
|
124
124
|
```css
|
|
125
125
|
@reference "./global.css";
|
|
126
126
|
```
|
|
127
|
-
Without it, the build breaks at release time with `Cannot apply unknown utility class 'gap-
|
|
127
|
+
Without it, the build breaks at release time with `Cannot apply unknown utility class 'gap-3' …` even though `tsc` and `astro check` pass clean — only the bundler catches it.
|
|
128
128
|
- **Fail loud, never silently.** If data is missing, a required field is absent, or an REST call returns an unexpected shape, return `status: "failed"` with details. Do not invent placeholders or swallow errors.
|
|
129
129
|
|
|
130
130
|
## Return contract
|
|
@@ -188,7 +188,7 @@ The `data` shapes for the scopes this file owns — `components` and `pages`/`pa
|
|
|
188
188
|
| Issuing REST calls from a `components` or `pages` scope | Components/Pages are frontend-only; read `seeded` data from your `.wix/seeded.json` slice (pages only) — never curl |
|
|
189
189
|
| Re-querying when your `seeded.<vertical>` slice is missing from `.wix/seeded.json` | Fail fast with `SEEDED_JSON_SLICE_MISSING` — an upstream phase didn't complete (do NOT re-query) |
|
|
190
190
|
| Depending on mutable shared state the orchestrator holds in scratch | Every input is inlined; the one shared file you may read is your `.wix/seeded.json` slice (read-only) |
|
|
191
|
-
| Inventing class names for layout/spacing/typography (`.productCard`, `.heroSection`) | Tailwind utilities derived from `@theme` tokens (`class="flex flex-col gap-
|
|
191
|
+
| Inventing class names for layout/spacing/typography (`.productCard`, `.heroSection`) | Tailwind utilities derived from `@theme` tokens (`class="flex flex-col gap-4"`, `class="py-24"`). For one-off page decoration, co-located `<style>` block. |
|
|
192
192
|
| Removing a marker after inserting at it | Marker stays; other verticals may contribute after you |
|
|
193
193
|
| Trailing narrative prose after the return JSON | JSON block must be the last content |
|
|
194
194
|
| Fabricated timestamps in the return JSON | Do not include timing fields — orchestrator captures them |
|
|
@@ -8,15 +8,15 @@ Every visual decision in a generated site falls into one of three categories. Ea
|
|
|
8
8
|
|
|
9
9
|
| Category | Lives in | Owned by | Use for |
|
|
10
10
|
|---|---|---|---|
|
|
11
|
-
| **Tokens (composed as utilities)** | the canonical `DESIGN.md` + its projections: the `@theme` block in `src/styles/global.css` (written by `scripts/compose.mjs`), plus `.wix/design-tokens.css` and `.wix/site.d.ts` (written by `scripts/emit-design-tokens.mjs`) — all from Designer's `DESIGN.md` | Designer picks values (Phase 2); `compose.mjs` writes `@theme` | All color,
|
|
11
|
+
| **Tokens (composed as utilities)** | the canonical `DESIGN.md` + its projections: the `@theme` block in `src/styles/global.css` (written by `scripts/compose.mjs`), plus `.wix/design-tokens.css` and `.wix/site.d.ts` (written by `scripts/emit-design-tokens.mjs`) — all from Designer's `DESIGN.md` | Designer picks values (Phase 2); `compose.mjs` writes `@theme` | All color, typography scale, radii, aspect ratios, shadows, transitions (spacing is Tailwind's built-in numeric scale). Pages compose tokens at call sites as Tailwind utilities — `class="py-24 bg-sand aspect-[16/5]"`. |
|
|
12
12
|
| **Global semantic classes** | `src/styles/global.css` (outside `@theme`) and `src/styles/components-<pack>.css` | Designer + Phase 3 component agents | Compound multi-element patterns, interactive states (`:hover`, `:focus`, `:disabled`), and JS/React DOM query targets. |
|
|
13
13
|
| **Co-located styles** | `<style>` block at the bottom of the same `.astro` file (or component CSS module for islands) | Page or component author | One-off page decoration: hero stamps, custom dividers, ornamental overlays that won't be reused elsewhere. |
|
|
14
14
|
|
|
15
15
|
## Default direction
|
|
16
16
|
|
|
17
|
-
**Tokens-as-utilities is the default.** When you're about to write a class for layout, spacing, typography, alignment, simple background/text color, or aspect ratio, write Tailwind utilities derived from `@theme` instead. The site's design tokens give you `
|
|
17
|
+
**Tokens-as-utilities is the default.** When you're about to write a class for layout, spacing, typography, alignment, simple background/text color, or aspect ratio, write Tailwind utilities derived from `@theme` instead. The site's design tokens give you `bg-paper-warm`, `text-ink`, `font-display`, `aspect-[16/5]` etc.; spacing is Tailwind-numeric (`py-24`, `gap-3`). Compose them in markup; do not invent semantic classes for these concerns.
|
|
18
18
|
|
|
19
|
-
The token namespace is the contract. The design tokens (the DESIGN.md token vocabulary — `colors`/`typography`/`
|
|
19
|
+
The token namespace is the contract. The design tokens (the DESIGN.md token vocabulary — `colors`/`typography`/`rounded`/`containers`) live on disk at `.wix/design-tokens.css` (gate-verified present before the build wave) — **read that file at the start of any pages or components scope** to know which tokens this run published. The orchestrator does **not** inline them in your prompt. (`.wix/site.d.ts` is also on disk for the build.) If a token you need isn't in `.wix/design-tokens.css`, that's a designer-side gap — flag it in your return JSON, don't paper over it with a custom class.
|
|
20
20
|
|
|
21
21
|
## Decision tree
|
|
22
22
|
|
|
@@ -32,24 +32,22 @@ If none fit, you're probably trying to do something the tokens don't support yet
|
|
|
32
32
|
|
|
33
33
|
These are layout/spacing/typography concerns that should always be utilities, never standalone classes:
|
|
34
34
|
|
|
35
|
-
- Section padding / margins (`py-
|
|
36
|
-
- Flex / grid layouts (`flex flex-col gap-
|
|
35
|
+
- Section padding / margins (`py-24`, `mt-16`, `mb-12`)
|
|
36
|
+
- Flex / grid layouts (`flex flex-col gap-4`, `grid grid-cols-3 gap-6`)
|
|
37
37
|
- Aspect ratios (`aspect-[4/5]`, `aspect-square`)
|
|
38
38
|
- Plain typography choices (`text-display-lg font-display`, `text-mute uppercase tracking-wide`)
|
|
39
39
|
- Background / foreground color application without state (`bg-paper`, `text-ink-soft`)
|
|
40
|
-
- Container widths
|
|
40
|
+
- Container widths (`max-w-prose`, `max-w-6xl`, `max-w-3xl`, `w-full`) — these resolve to the `--container-*` keys the designer declared.
|
|
41
41
|
|
|
42
|
-
###
|
|
42
|
+
### Spacing & reading width
|
|
43
43
|
|
|
44
|
-
Tailwind
|
|
44
|
+
**Spacing is Tailwind's built-in numeric scale** — `gap-4`, `py-24`, `px-6`, `mt-16`, etc. There is **no** named `--spacing-<size>` scale (it was removed: its t-shirt names `md`/`3xl`/… collided with the width utilities, so `max-w-3xl` resolved to `--spacing-3xl` ≈ 96px). Common steps: `1`=0.25rem, `2`=0.5, `3`=0.75, `4`=1rem, `6`=1.5, `8`=2, `12`=3, `16`=4, `24`=6rem.
|
|
45
45
|
|
|
46
|
-
**
|
|
46
|
+
> **Never reintroduce a named `--spacing-*` scale.** In Tailwind v4 the `--spacing-*` namespace also generates the width/sizing families (`max-w-*`, `w-*`, `min-w-*`, …), so any `--spacing-<key>` token shadows the matching `max-w-<key>`. The current fix works because the skill's spacing steps happen to equal Tailwind's numeric defaults — but if a brand ever needs genuinely *custom* spacing **values**, put them under a different namespace (e.g. `--rhythm-*`) or use arbitrary values (`py-[5.5rem]`); do not revive `--spacing-*`.
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
- **Prefer** `container-reading` (designer `@utility`), `max-w-6xl` when `--container-6xl` exists, or explicit arbitrary width `max-w-[48rem]`.
|
|
50
|
-
- **Do not** confuse spacing scale with container scale — `py-3xl` uses `--spacing-3xl`; `max-w-3xl` uses `--container-3xl`.
|
|
48
|
+
**Width / reading columns:** `max-w-md`, `max-w-3xl`, `max-w-6xl`, `max-w-prose` now resolve correctly to the `--container-*` keys (no spacing collision), so use them freely; `container-reading` (the designer `@utility`) or an arbitrary `max-w-[48rem]` also work.
|
|
51
49
|
|
|
52
|
-
If a designer's `global.css` contains rules like `.featured-section { padding-block:
|
|
50
|
+
If a designer's `global.css` contains rules like `.featured-section { padding-block: 6rem; }` or `.product-card-body { display: flex; flex-direction: column; gap: 0.5rem; }`, those are misplaced — they belong in markup as utilities (`py-24`, `flex flex-col gap-2`). Inventing such classes ships broken layouts: every consumer needs the designer to have pre-declared the class, and Tailwind v4 silently drops the references when the rule is missing.
|
|
53
51
|
|
|
54
52
|
## Required tokens — the component-CSS template contract
|
|
55
53
|
|
|
@@ -68,11 +66,10 @@ The per-pack `components-<pack>.css` templates at `<SKILL_ROOT>/references/astro
|
|
|
68
66
|
| `--color-error` | optional | `var(--color-accent)` or hardcode | ecom cart-item-unavailable, stores back-in-stock-error |
|
|
69
67
|
| `--font-display` | **required** | — | every pack — headings + labels |
|
|
70
68
|
| `--font-body` | **required** | — | every pack — body text + UI |
|
|
71
|
-
| `--spacing-2xs` … `--spacing-4xl` | **required (full scale)** | — | every template uses `gap: var(--spacing-md)` and similar |
|
|
72
69
|
| `--radius-sm`, `--radius-md` | **required** | — | buttons, inputs, cards |
|
|
73
70
|
| `--radius-lg`, `--radius-xl` | optional | — | stores product-card |
|
|
74
71
|
|
|
75
|
-
The templates do NOT use `@apply` — every rule is `property: var(--token);` directly. This means missing utilities don't fail at build time (the way `@apply gap-
|
|
72
|
+
The templates do NOT use `@apply` — every rule is `property: var(--token);` directly. This means missing utilities don't fail at build time (the way `@apply gap-3` would). Missing tokens degrade silently to `var(missing) → unset → initial`. That makes the failure mode "ugly component" not "broken build" — easier to recover from but harder to detect, so verify the full set above is in `@theme` before returning.
|
|
76
73
|
|
|
77
74
|
**Why this contract exists.** The component templates are authored against a stable, brand-agnostic token vocabulary so they don't need to be regenerated per run. Using `@apply` against brand-specific tokens (e.g. `bark`, `cream`, `parchment`) that designers don't publish fails the build with `Cannot apply unknown utility class`. Direct `var()` against the required-token list above avoids that class of failure entirely.
|
|
78
75
|
|
|
@@ -119,15 +116,15 @@ For any listed class the Composer's `global.css` declares: if a template referen
|
|
|
119
116
|
Astro's `<style>` blocks scope automatically to the `.astro` file by default — no class-name collision risk across routes. When a page needs decoration that doesn't fit utilities and isn't reusable, the rule lives next to its only caller:
|
|
120
117
|
|
|
121
118
|
```astro
|
|
122
|
-
<section class="relative py-
|
|
119
|
+
<section class="relative py-24">
|
|
123
120
|
<div class="hero-stamp">Made in small batches</div>
|
|
124
121
|
</section>
|
|
125
122
|
|
|
126
123
|
<style>
|
|
127
124
|
.hero-stamp {
|
|
128
125
|
position: absolute;
|
|
129
|
-
bottom:
|
|
130
|
-
right:
|
|
126
|
+
bottom: 1.5rem;
|
|
127
|
+
right: 1.5rem;
|
|
131
128
|
background: rgba(27, 26, 23, 0.75);
|
|
132
129
|
color: var(--color-paper);
|
|
133
130
|
padding: 0.5rem 0.875rem;
|
|
@@ -95,8 +95,8 @@ If you find one of these missing at runtime, that's an orchestrator-side bug —
|
|
|
95
95
|
|
|
96
96
|
Stores-specific component CSS lives in `src/styles/components-stores.css` (pre-copied from the template by the orchestrator before Step 4.5 — see the `components` scope-routing note above and `../astro/stores/COMPONENTS_CSS.md`), NOT in the designer's `global.css`. The classes the pack owns:
|
|
97
97
|
|
|
98
|
-
- `.product-card`, `.product-card-media`, `.product-card-ribbon`, `.product-card-index` — the product card itself, including the `overflow: hidden` + `border-radius` clipping context. Whoever writes the `border-radius` here also writes any inner padding required to keep child content inside the rounded edges. Without inner padding, a price `<p>` sits flush against the rounded bottom corner and descenders get clipped. Add `padding-bottom:
|
|
99
|
-
- `.product-grid` — the layout that lists product cards. Both `/products` (pages-products scope) and `/category/[slug]` (pages-categories scope) consume it from one place. Include `display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap:
|
|
98
|
+
- `.product-card`, `.product-card-media`, `.product-card-ribbon`, `.product-card-index` — the product card itself, including the `overflow: hidden` + `border-radius` clipping context. Whoever writes the `border-radius` here also writes any inner padding required to keep child content inside the rounded edges. Without inner padding, a price `<p>` sits flush against the rounded bottom corner and descenders get clipped. Add `padding-bottom: 1rem` on the card plus horizontal padding on each text block when you set the radius. See `references/shared/STYLING.md` § "Component-specific CSS is owned by the component, not the designer".
|
|
99
|
+
- `.product-grid` — the layout that lists product cards. Both `/products` (pages-products scope) and `/category/[slug]` (pages-categories scope) consume it from one place. Include `display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 2rem;` plus the View-Transitions opacity fade for in-flight navigations.
|
|
100
100
|
- `.offer-callout` family (`.offer-callout`, `-item`, `-badge`, `-name`, `-detail`, `-foot`) — discount panel rendered above `<ProductPurchase>` on `/products/[slug]`.
|
|
101
101
|
|
|
102
102
|
The designer's `global.css` declares only tokens, the `.btn` family, decorative slots, the editorial-rule, and the site-shell shells. If `global.css` ships with a partial rule for any class above, that's a designer bug — flag it in your return JSON's `errors` array (`{code: "GLOBAL_CSS_LEAK", class: "<name>"}`) and override with the complete rule in `components-stores.css`.
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: bookings
|
|
3
|
-
description: "Service-based booking — services catalog, availability calendar, and booking flow via Wix Bookings."
|
|
3
|
+
description: "Service-based booking — services catalog (with location + category filters and staff selection), availability calendar, and booking flow for appointments and classes via Wix Bookings."
|
|
4
4
|
triggers: ["booking", "appointment", "schedule", "reserve", "class", "session", "consult", "therapy", "lesson", "coaching", "trainer", "tutor", "salon", "spa", "clinic"]
|
|
5
5
|
requires: []
|
|
6
6
|
|
|
7
7
|
features:
|
|
8
8
|
- name: "Services catalog"
|
|
9
|
-
description: "Browse bookable appointment services with descriptions, duration, and pricing."
|
|
9
|
+
description: "Browse bookable appointment and class services with descriptions, duration, and pricing — filterable by category and (for multi-location businesses) by location."
|
|
10
|
+
- name: "Staff selection"
|
|
11
|
+
description: "On multi-staff services, choose a specific staff member (or any) and see that staff's availability."
|
|
10
12
|
- name: "Online booking"
|
|
11
|
-
description: "Pick an available time slot on a calendar, complete the service's booking form, and confirm."
|
|
13
|
+
description: "Pick an available time slot on a day-grouped availability calendar, complete the service's booking form, and confirm."
|
|
12
14
|
- name: "Secure checkout"
|
|
13
15
|
description: "Free or pay-in-person bookings confirm instantly; paid services hand off to Wix's secure hosted checkout."
|
|
14
16
|
|
|
@@ -192,7 +192,6 @@ function designMdToTokens(fm) {
|
|
|
192
192
|
return {
|
|
193
193
|
colors,
|
|
194
194
|
fonts,
|
|
195
|
-
spacing: fm.spacing ?? {},
|
|
196
195
|
radii: fm.rounded ?? {}, // DESIGN.md calls corner radii `rounded`
|
|
197
196
|
containers: fm.containers ?? {}, // custom group
|
|
198
197
|
...(typeof fm.googleFontsHref === "string" ? { googleFontsHref: fm.googleFontsHref } : {}),
|
|
@@ -241,7 +240,6 @@ const SYSTEM_FONTS = new Set([
|
|
|
241
240
|
|
|
242
241
|
const colors = { ...(designTokens.colors ?? {}) };
|
|
243
242
|
const fonts = { ...(designTokens.fonts ?? {}) };
|
|
244
|
-
const spacing = { ...(designTokens.spacing ?? {}) };
|
|
245
243
|
const radii = { ...(designTokens.radii ?? {}) };
|
|
246
244
|
const containers = { ...(designTokens.containers ?? {}) };
|
|
247
245
|
|
|
@@ -272,12 +270,10 @@ ensure(colors, "error", "#c0392b", "--color-");
|
|
|
272
270
|
ensure(fonts, "display", "Georgia, serif", "--font-");
|
|
273
271
|
ensure(fonts, "body", "system-ui, sans-serif", "--font-");
|
|
274
272
|
|
|
275
|
-
// Spacing —
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
};
|
|
280
|
-
for (const [k, v] of Object.entries(SPACING_DEFAULTS)) ensure(spacing, k, v, "--spacing-");
|
|
273
|
+
// Spacing is NOT a named scale — Tailwind v4's built-in numeric spacing
|
|
274
|
+
// (`--spacing` base → gap-4, py-24, …) is used directly. Emitting named
|
|
275
|
+
// --spacing-<t-shirt> tokens collided with the width utilities (max-w-3xl etc.
|
|
276
|
+
// drew from --spacing-3xl), so the named scale was removed (CODEAI-696).
|
|
281
277
|
|
|
282
278
|
// Radii — sm + md required.
|
|
283
279
|
ensure(radii, "sm", "0.25rem", "--radius-");
|
|
@@ -296,8 +292,6 @@ emitGroup("--color-", colors);
|
|
|
296
292
|
themeLines.push("");
|
|
297
293
|
emitGroup("--font-", fonts);
|
|
298
294
|
themeLines.push("");
|
|
299
|
-
emitGroup("--spacing-", spacing);
|
|
300
|
-
themeLines.push("");
|
|
301
295
|
emitGroup("--radius-", radii);
|
|
302
296
|
themeLines.push("");
|
|
303
297
|
emitGroup("--container-", containers);
|
|
@@ -310,14 +304,12 @@ const errors = [];
|
|
|
310
304
|
const REQUIRED = [
|
|
311
305
|
...["paper", "paper-warm", "ink", "mute", "rule", "accent"].map((k) => `--color-${k}`),
|
|
312
306
|
"--font-display", "--font-body",
|
|
313
|
-
...["2xs", "xs", "sm", "md", "lg", "xl", "2xl", "3xl", "4xl"].map((k) => `--spacing-${k}`),
|
|
314
307
|
"--radius-sm", "--radius-md",
|
|
315
308
|
...["prose", "md", "3xl", "6xl"].map((k) => `--container-${k}`),
|
|
316
309
|
];
|
|
317
310
|
const present = new Set([
|
|
318
311
|
...Object.keys(colors).map((k) => `--color-${k}`),
|
|
319
312
|
...Object.keys(fonts).map((k) => `--font-${k}`),
|
|
320
|
-
...Object.keys(spacing).map((k) => `--spacing-${k}`),
|
|
321
313
|
...Object.keys(radii).map((k) => `--radius-${k}`),
|
|
322
314
|
...Object.keys(containers).map((k) => `--container-${k}`),
|
|
323
315
|
]);
|
|
@@ -325,12 +317,6 @@ for (const tok of REQUIRED) {
|
|
|
325
317
|
if (!present.has(tok)) errors.push({ code: "MISSING_REQUIRED_TOKEN", token: tok });
|
|
326
318
|
}
|
|
327
319
|
|
|
328
|
-
// Container ≠ spacing: a --container-* value must never equal a --spacing-* value.
|
|
329
|
-
const spacingValues = new Set(Object.values(spacing));
|
|
330
|
-
for (const [k, v] of Object.entries(containers)) {
|
|
331
|
-
if (spacingValues.has(v)) errors.push({ code: "CONTAINER_EQUALS_SPACING", token: `--container-${k}`, value: v });
|
|
332
|
-
}
|
|
333
|
-
|
|
334
320
|
// ── skeleton load + substitution helpers ──────────────────────────────────────
|
|
335
321
|
function readTemplate(name) {
|
|
336
322
|
const p = join(TEMPLATES, name);
|
|
@@ -526,7 +512,6 @@ const manifest = {
|
|
|
526
512
|
homeMarkers: homeMarkerPacks.map((p) => `home:${p}`),
|
|
527
513
|
tokensApplied: {
|
|
528
514
|
colors: Object.keys(colors).length,
|
|
529
|
-
spacing: Object.keys(spacing).length,
|
|
530
515
|
containers: Object.keys(containers).length,
|
|
531
516
|
radii: Object.keys(radii).length,
|
|
532
517
|
fonts: Object.keys(fonts).length,
|
|
@@ -115,7 +115,6 @@ if (!design || typeof design !== "object" || Object.keys(design).length === 0) {
|
|
|
115
115
|
|
|
116
116
|
const colors = design.colors ?? {};
|
|
117
117
|
const typography = design.typography ?? {};
|
|
118
|
-
const spacing = design.spacing ?? {};
|
|
119
118
|
const rounded = design.rounded ?? {};
|
|
120
119
|
const containers = design.containers ?? {};
|
|
121
120
|
const fontFamilyOf = (lvl) => (typography[lvl] && typeof typography[lvl] === "object" ? typography[lvl].fontFamily : typography[lvl]);
|
|
@@ -136,7 +135,6 @@ for (const lvl of Object.keys(typography)) {
|
|
|
136
135
|
if (fam) cssLines.push(` --font-${lvl}: ${fam};`);
|
|
137
136
|
}
|
|
138
137
|
for (const [k, v] of Object.entries(rounded)) cssLines.push(` --radius-${k}: ${v};`);
|
|
139
|
-
for (const [k, v] of Object.entries(spacing)) cssLines.push(` --spacing-${k}: ${v};`);
|
|
140
138
|
for (const [k, v] of Object.entries(containers)) cssLines.push(` --container-${k}: ${v};`);
|
|
141
139
|
cssLines.push("}", "");
|
|
142
140
|
writeFileSync(join(wixDir, "design-tokens.css"), cssLines.join("\n"));
|
|
@@ -151,7 +149,6 @@ export type DesignTokens = {
|
|
|
151
149
|
colors: ${recordType(Object.keys(colors))};
|
|
152
150
|
fonts: ${recordType(Object.keys(typography))};
|
|
153
151
|
radii: ${recordType(Object.keys(rounded))};
|
|
154
|
-
spacing: ${recordType(Object.keys(spacing))};
|
|
155
152
|
containers: ${recordType(Object.keys(containers))};
|
|
156
153
|
};
|
|
157
154
|
`;
|
|
@@ -13,7 +13,6 @@ description: "Create an appointment booking service — e.g. 'set up consultatio
|
|
|
13
13
|
|
|
14
14
|
## Prerequisites
|
|
15
15
|
|
|
16
|
-
- **Wix Bookings app installed** (App ID: `13d21c63-b5ec-5912-8397-c3a5ddb27a97`). Use [List Installed Apps](../app-installation/list-installed-apps.md) to verify, and [Install Wix Apps](../app-installation/install-wix-apps.md) to install if missing.
|
|
17
16
|
- For full API field definitions, validation rules, and troubleshooting, see [Create and Update Booking Services](./create-and-update-booking-services.md)
|
|
18
17
|
|
|
19
18
|
---
|
|
@@ -47,16 +46,7 @@ curl -X POST 'https://www.wixapis.com/bookings/v2/categories/query' \
|
|
|
47
46
|
-d '{ "query": {} }'
|
|
48
47
|
```
|
|
49
48
|
|
|
50
|
-
### 1c.
|
|
51
|
-
|
|
52
|
-
```bash
|
|
53
|
-
curl -X GET 'https://www.wixapis.com/site-properties/v4/properties' \
|
|
54
|
-
-H 'Authorization: <AUTH>'
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
Extract `properties.paymentCurrency`. Fall back to `USD` if unavailable.
|
|
58
|
-
|
|
59
|
-
### 1d. Query Existing Services (Duplicate Check)
|
|
49
|
+
### 1c. Query Existing Services (Duplicate Check)
|
|
60
50
|
|
|
61
51
|
```bash
|
|
62
52
|
curl -X POST 'https://www.wixapis.com/bookings/v2/services/query' \
|
|
@@ -82,7 +72,6 @@ For any fields the user did not explicitly specify:
|
|
|
82
72
|
|
|
83
73
|
### Pricing (if not specified)
|
|
84
74
|
|
|
85
|
-
- Use the site's currency from Step 1c
|
|
86
75
|
- If user specifies a price → `rateType: "FIXED"`
|
|
87
76
|
- If user says "free" → `rateType: "NO_FEE"`, `options.inPerson: true`, `options.online: false`
|
|
88
77
|
- If no price mentioned → infer from context (consultations ~$50-100, sessions ~$30-60) or default to free
|
|
@@ -136,7 +125,7 @@ curl -X POST 'https://www.wixapis.com/bookings/v2/bulk/services/create' \
|
|
|
136
125
|
"rateType": "FIXED",
|
|
137
126
|
"options": { "online": true, "inPerson": false },
|
|
138
127
|
"fixed": {
|
|
139
|
-
"price": { "value": "<PRICE>"
|
|
128
|
+
"price": { "value": "<PRICE>" }
|
|
140
129
|
}
|
|
141
130
|
},
|
|
142
131
|
"category": {
|
|
@@ -186,19 +175,7 @@ Save the `serviceId` from the response: `results[0].item.service.id`
|
|
|
186
175
|
|
|
187
176
|
---
|
|
188
177
|
|
|
189
|
-
## Step 4:
|
|
190
|
-
|
|
191
|
-
Use the **RUN_IN_BROWSER** tool to navigate the user to the service form for final review:
|
|
192
|
-
|
|
193
|
-
```javascript
|
|
194
|
-
window.location.href = `/bookings/services/form/${serviceId}?fromAria=true`;
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
This executes in the user's browser and redirects them to the service editing page.
|
|
198
|
-
|
|
199
|
-
---
|
|
200
|
-
|
|
201
|
-
## Step 5: Summary Message
|
|
178
|
+
## Step 4: Summary Message
|
|
202
179
|
|
|
203
180
|
Provide a summary including:
|
|
204
181
|
|
|
@@ -225,7 +202,6 @@ Provide a summary including:
|
|
|
225
202
|
|
|
226
203
|
| Error | Cause | Action |
|
|
227
204
|
|---|---|---|
|
|
228
|
-
| 428 "App not installed" | Bookings not installed | Install using [Install Wix Apps](../app-installation/install-wix-apps.md) |
|
|
229
205
|
| 400 "staffMemberIds required" | No staff assigned | Query staff; if none exist, create one via [Bookings Staff Setup](./bookings-staff-setup.md) |
|
|
230
206
|
| 400 "INVALID_PAYMENT_OPTIONS" | Payment misconfigured | Free: `inPerson: true`, `online: false`. Paid: price > 0 |
|
|
231
207
|
| 403 | Permission denied | Inform user they lack permission |
|
|
@@ -261,6 +237,5 @@ Provide a summary including:
|
|
|
261
237
|
- [Create Category](https://dev.wix.com/docs/api-reference/business-solutions/bookings/services/categories-v2/create-category)
|
|
262
238
|
- [Query Staff Members](https://dev.wix.com/docs/api-reference/business-solutions/bookings/staff-members/staff-members/query-staff-members)
|
|
263
239
|
- [Create Staff Member](https://dev.wix.com/docs/api-reference/business-solutions/bookings/staff-members/staff-members/create-staff-member)
|
|
264
|
-
- [Site Properties](https://dev.wix.com/docs/api-reference/business-management/site-management/site-properties/properties/read)
|
|
265
240
|
- [About Service Types](https://dev.wix.com/docs/api-reference/business-solutions/bookings/services/services-v2/about-service-types)
|
|
266
241
|
- [About Service Payments](https://dev.wix.com/docs/api-reference/business-solutions/bookings/services/services-v2/about-service-payments)
|
|
@@ -10,13 +10,6 @@ description: "Create a booking service from a user prompt — e.g. 'create a yog
|
|
|
10
10
|
- User describes a service they want to create using natural language (e.g., "create a yoga class for $50", "set up consultation sessions", "add a personal training appointment")
|
|
11
11
|
- The intent is autonomous creation — fill in reasonable defaults rather than asking the user for every field
|
|
12
12
|
|
|
13
|
-
## Prerequisites
|
|
14
|
-
|
|
15
|
-
- **Wix Bookings app installed** (App ID: `13d21c63-b5ec-5912-8397-c3a5ddb27a97`)
|
|
16
|
-
- If Bookings is not installed, use [Install Wix Apps](../app-installation/install-wix-apps.md) to install it first
|
|
17
|
-
|
|
18
|
-
---
|
|
19
|
-
|
|
20
13
|
## Step 1: Determine Service Type
|
|
21
14
|
|
|
22
15
|
| User mentions | Type | Recipe |
|
|
@@ -30,7 +23,7 @@ description: "Create a booking service from a user prompt — e.g. 'create a yog
|
|
|
30
23
|
|
|
31
24
|
Once the service type is determined, follow the corresponding recipe linked above. Each recipe covers:
|
|
32
25
|
|
|
33
|
-
1. Gathering business context (staff, categories,
|
|
26
|
+
1. Gathering business context (staff where required, categories, duplicate check)
|
|
34
27
|
2. Applying type-specific defaults (pricing, capacity, duration, staff assignment)
|
|
35
28
|
3. Creating the service via `bulkCreateServices`
|
|
36
29
|
4. Navigating to the service form for user review
|
|
@@ -14,7 +14,6 @@ description: "Create a class booking service — e.g. 'create a yoga class for $
|
|
|
14
14
|
|
|
15
15
|
## Prerequisites
|
|
16
16
|
|
|
17
|
-
- **Wix Bookings app installed** (App ID: `13d21c63-b5ec-5912-8397-c3a5ddb27a97`). Use [List Installed Apps](../app-installation/list-installed-apps.md) to verify, and [Install Wix Apps](../app-installation/install-wix-apps.md) to install if missing.
|
|
18
17
|
- For full API field definitions, validation rules, and troubleshooting, see [Create and Update Booking Services](./create-and-update-booking-services.md)
|
|
19
18
|
|
|
20
19
|
---
|
|
@@ -32,16 +31,7 @@ curl -X POST 'https://www.wixapis.com/bookings/v2/categories/query' \
|
|
|
32
31
|
-d '{ "query": {} }'
|
|
33
32
|
```
|
|
34
33
|
|
|
35
|
-
### 1b.
|
|
36
|
-
|
|
37
|
-
```bash
|
|
38
|
-
curl -X GET 'https://www.wixapis.com/site-properties/v4/properties' \
|
|
39
|
-
-H 'Authorization: <AUTH>'
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
Extract `properties.paymentCurrency`. Fall back to `USD` if unavailable.
|
|
43
|
-
|
|
44
|
-
### 1c. Query Existing Services (Duplicate Check)
|
|
34
|
+
### 1b. Query Existing Services (Duplicate Check)
|
|
45
35
|
|
|
46
36
|
```bash
|
|
47
37
|
curl -X POST 'https://www.wixapis.com/bookings/v2/services/query' \
|
|
@@ -67,7 +57,6 @@ For any fields the user did not explicitly specify:
|
|
|
67
57
|
|
|
68
58
|
### Pricing (if not specified)
|
|
69
59
|
|
|
70
|
-
- Use the site's currency from Step 1b
|
|
71
60
|
- If user specifies a price → `rateType: "FIXED"` (per session)
|
|
72
61
|
- If user says "free" → `rateType: "NO_FEE"`, `options.inPerson: true`, `options.online: false`
|
|
73
62
|
- If no price mentioned → infer from context (yoga/fitness classes ~$15-30, art/music ~$20-40) or default to free
|
|
@@ -118,7 +107,7 @@ curl -X POST 'https://www.wixapis.com/bookings/v2/bulk/services/create' \
|
|
|
118
107
|
"rateType": "FIXED",
|
|
119
108
|
"options": { "online": true, "inPerson": false },
|
|
120
109
|
"fixed": {
|
|
121
|
-
"price": { "value": "<PRICE>"
|
|
110
|
+
"price": { "value": "<PRICE>" }
|
|
122
111
|
}
|
|
123
112
|
},
|
|
124
113
|
"category": {
|
|
@@ -164,19 +153,7 @@ Save the `serviceId` from the response: `results[0].item.service.id`
|
|
|
164
153
|
|
|
165
154
|
---
|
|
166
155
|
|
|
167
|
-
## Step 4:
|
|
168
|
-
|
|
169
|
-
Use the **RUN_IN_BROWSER** tool to navigate the user to the service form for final review:
|
|
170
|
-
|
|
171
|
-
```javascript
|
|
172
|
-
window.location.href = `/bookings/services/form/${serviceId}?fromAria=true`;
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
This executes in the user's browser and redirects them to the service editing page.
|
|
176
|
-
|
|
177
|
-
---
|
|
178
|
-
|
|
179
|
-
## Step 5: Summary Message
|
|
156
|
+
## Step 4: Summary Message
|
|
180
157
|
|
|
181
158
|
Provide a summary including:
|
|
182
159
|
|
|
@@ -205,7 +182,6 @@ Provide a summary including:
|
|
|
205
182
|
|
|
206
183
|
| Error | Cause | Action |
|
|
207
184
|
|---|---|---|
|
|
208
|
-
| 428 "App not installed" | Bookings not installed | Install using [Install Wix Apps](../app-installation/install-wix-apps.md) |
|
|
209
185
|
| 400 "INVALID_PAYMENT_OPTIONS" | Payment misconfigured | Free: `inPerson: true`, `online: false`. Paid: price > 0 |
|
|
210
186
|
| 403 | Permission denied | Inform user they lack permission |
|
|
211
187
|
|
|
@@ -240,6 +216,5 @@ Provide a summary including:
|
|
|
240
216
|
- [Query Categories](https://dev.wix.com/docs/api-reference/business-solutions/bookings/services/categories-v2/query-categories)
|
|
241
217
|
- [Create Category](https://dev.wix.com/docs/api-reference/business-solutions/bookings/services/categories-v2/create-category)
|
|
242
218
|
- [Bulk Create Events](https://dev.wix.com/docs/api-reference/business-management/calendar/events-v3/bulk-create-event)
|
|
243
|
-
- [Site Properties](https://dev.wix.com/docs/api-reference/business-management/site-management/site-properties/properties/read)
|
|
244
219
|
- [About Service Types](https://dev.wix.com/docs/api-reference/business-solutions/bookings/services/services-v2/about-service-types)
|
|
245
220
|
- [About Service Payments](https://dev.wix.com/docs/api-reference/business-solutions/bookings/services/services-v2/about-service-payments)
|