@wix/agent-skills 1.19.0 → 1.19.1

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.
Files changed (58) hide show
  1. package/package.json +1 -1
  2. package/skills/wix-app/SKILL.md +33 -31
  3. package/skills/wix-app/references/DASHBOARD_PAGE.md +6 -10
  4. package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +16 -7
  5. package/skills/wix-app/references/WIX_PATTERNS_DOCS.md +53 -131
  6. package/skills/wix-app/references/dashboard-page/UX_SUCCESS_MODEL.md +1 -2
  7. package/skills/wix-app/references/editor-react-component/ACCESSIBILITY.md +83 -73
  8. package/skills/wix-app/references/editor-react-component/COMPONENT-CONTRACT.md +3 -2
  9. package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +9 -0
  10. package/skills/wix-app/references/editor-react-component/PARTS.md +5 -2
  11. package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +1 -1
  12. package/skills/wix-app/scripts/pkg-root.cjs +73 -0
  13. package/skills/wix-app/scripts/scan-a11y-code.cjs +310 -40
  14. package/skills/wix-app/scripts/scan-a11y-eslint.cjs +118 -24
  15. package/skills/wix-app/scripts/scan-a11y-render.cjs +551 -0
  16. package/skills/wix-app/scripts/scan-a11y-review.cjs +373 -0
  17. package/skills/wix-base44-connector/SKILL.md +24 -22
  18. package/skills/wix-base44-connector/scripts/utils.cjs +39 -3
  19. package/skills/wix-docs/SKILL.md +47 -20
  20. package/skills/wix-headless/entry/bootstrap.mjs +106 -50
  21. package/skills/wix-headless/entry/skill.md +5 -3
  22. package/skills/wix-headless/references/managed/AUTHENTICATION.md +25 -5
  23. package/skills/wix-headless-fast/SKILL.md +25 -7
  24. package/skills/wix-headless-fast/entry/skill.md +23 -14
  25. package/skills/wix-headless-fast/install/fast-path.mjs +48 -5
  26. package/skills/wix-headless-fast/install/pin-agents-md.mjs +57 -0
  27. package/skills/wix-headless-fast/references/shared/CUSTOM_OPERATIONS.md +3 -3
  28. package/skills/wix-headless-fast/references/storefront/INSTRUCTIONS.md +204 -35
  29. package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useShop.ts +146 -36
  30. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart-store.ts +8 -2
  31. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/catalog.ts +95 -20
  32. package/skills/wix-headless-fast/references/storefront/seed/SEED.md +21 -2
  33. package/skills/wix-headless-fast/references/storefront/seed/seed-store.mjs +104 -18
  34. package/skills/wix-manage/SKILL.md +13 -7
  35. package/skills/wix-manage/references/google-ads/billing-and-payment.md +3 -3
  36. package/skills/wix-manage/references/google-ads/create-performance-max-campaign.md +8 -8
  37. package/skills/wix-manage/references/google-ads/get-campaign-suggestions.md +4 -4
  38. package/skills/wix-manage/references/google-ads/google-ads-dashboard-navigation.md +1 -1
  39. package/skills/wix-manage/references/google-ads/install-and-create-account.md +9 -9
  40. package/skills/wix-manage/references/google-ads/query-campaign-analytics.md +7 -7
  41. package/skills/wix-manage/references/seo/manage-content-plan.md +181 -135
  42. package/skills/wix-manage/references/seo/manage-google-search-console.md +272 -0
  43. package/skills/wix-manage/references/sites/upload-static-site.md +53 -0
  44. package/skills/wix-manage/references/stores/change-store-currency.md +1 -1
  45. package/skills/wix-vibe-headless/platforms/base44-ecom-light-seed-with-install.md +3 -1
  46. package/skills/wix-vibe-headless/platforms/base44-ecom-light-seed.md +3 -1
  47. package/skills/wix-vibe-headless/platforms/base44-ecom-light.md +1 -1
  48. package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +1 -1
  49. package/skills/wix-app/references/dashboard-page/COLLECTION_TOOLKIT.md +0 -80
  50. package/skills/wix-app/references/dashboard-page/ENTITY_PAGE_TOOLKIT.md +0 -140
  51. package/skills/wix-app/references/dashboard-page/PATTERNS_BUNDLE_READING.md +0 -112
  52. package/skills/wix-headless-fast/references/storefront/app/components/storefront/ProductCard.tsx +0 -100
  53. package/skills/wix-headless-fast/references/storefront/app/components/storefront/ProductDetailView.tsx +0 -130
  54. package/skills/wix-headless-fast/references/storefront/app/components/storefront/ProductGrid.tsx +0 -48
  55. package/skills/wix-headless-fast/references/storefront/app/components/storefront/ShopView.tsx +0 -66
  56. package/skills/wix-headless-fast/references/storefront/app/components/storefront/VariantPicker.tsx +0 -103
  57. package/skills/wix-headless-fast/references/storefront/app-astro/pages/products/[slug].astro +0 -56
  58. package/skills/wix-headless-fast/references/storefront/app-astro/pages/shop.astro +0 -23
@@ -0,0 +1,272 @@
1
+ ---
2
+ name: "Manage Google Search Console for a Wix Site"
3
+ description: "Connect a Wix site to Google Search Console and drive its setup through the public GSC Connection and Site Readiness APIs: check connection and readiness, start the Google authorization, verify ownership, add the property, submit the sitemap, request indexing, read search performance, run URL inspection, recover a stale connection, or disconnect. The site owner authorizes in their own browser via a single-use connect URL."
4
+ ---
5
+
6
+ # Manage Google Search Console for a Wix Site
7
+
8
+ The **GSC Connection API** links a Google account to the site. The **GSC Site
9
+ Readiness API** acts through that account: verifies ownership, adds the Search
10
+ Console property, submits the sitemap, requests indexing, reads search performance
11
+ and URL inspection. Both select the site from the caller's authorization context
12
+ and take no site ID. Use the site already selected in the environment. If none is
13
+ selected, list the available sites. Select the only site automatically; if several
14
+ are available, ask the user to choose by name before making site-specific calls.
15
+ Never invent a site ID or ask the user to type one.
16
+
17
+ All endpoints are under `https://www.wixapis.com`: Connection calls under
18
+ `/gsc/connection/v1`, everything else under `/gsc/v1`.
19
+
20
+ ## Start every task with two reads
21
+
22
+ Both are side-effect free. Do them before describing the site's state.
23
+
24
+ ```
25
+ GET https://www.wixapis.com/gsc/connection/v1/connection
26
+ ```
27
+
28
+ ```json
29
+ { "connection": { "status": "VALID", "connectedEmailMasking": "m*******@gmail.com", "ownedByCaller": true } }
30
+ ```
31
+
32
+ ```
33
+ GET https://www.wixapis.com/gsc/v1/site-readiness
34
+ ```
35
+
36
+ ```json
37
+ { "siteReadiness": { "status": "NOT_READY", "blockingReason": "SITE_OWNER_NOT_VERIFIED" } }
38
+ ```
39
+
40
+ Read them together:
41
+
42
+ | `connection.status` | `siteReadiness` | Meaning | Next |
43
+ |---|---|---|---|
44
+ | `NOT_CONNECTED` | `NOT_READY` / `SITE_OWNER_NOT_VERIFIED` | No Google account linked | Connect (below) |
45
+ | `PENDING` | any | An authorization attempt is open | Ask the user to finish it in their browser, do not start another |
46
+ | `VALID` | `READY` | Connected and verified | Property steps if the user wants them |
47
+ | `VALID` | `NOT_READY` / `SITE_OWNER_NOT_VERIFIED` | Connected, not verified | Verify Site |
48
+ | `INVALID` | `NOT_READY` / `TOKEN_INVALID` | Credentials rejected by Google | Reconnect |
49
+ | `VALID` | `NOT_READY` / `DOMAIN_MISSING` | No connected domain | User connects a domain first |
50
+
51
+ `blockingReason` is `UNKNOWN_BLOCKING_REASON` when the status is `READY`; not an
52
+ error. Treat an unrecognized reason as "not ready, no known next action".
53
+
54
+ `READY` covers connection and verification only. Whether the property was added,
55
+ the sitemap submitted, or indexing requested comes from **List Events**.
56
+
57
+ ## `VALID` can be stale, and `MISSING_TOKEN` means reconnect
58
+
59
+ `INVALID` is only written when a real call to Google is rejected, so a site nobody
60
+ has queried since its credentials broke keeps reporting `VALID`. The tell arrives
61
+ on the first Google-facing call:
62
+
63
+ ```json
64
+ { "message": "FAILED_PRECONDITION: Missing Token", "details": { "applicationError": { "code": "MISSING_TOKEN" } } }
65
+ ```
66
+
67
+ The reference describes `MISSING_TOKEN` as "no Google account is connected"; it
68
+ also fires when the stored credentials are gone while Get Connection still said
69
+ `VALID`. Either way: the Google account must be reconnected. Do not retry, and do
70
+ not tell the user the site is connected.
71
+
72
+ ## Connect a Google account
73
+
74
+ Get Connect URL is `GET`, but it **writes**: every call starts a new single-use
75
+ authorization attempt (two-hour expiry) and Get Connection reports `PENDING` while
76
+ it is open. Use Get Connection to check connection status. Call Get Connect URL
77
+ when starting a connection or reconnection attempt; while the user completes that
78
+ attempt, use Get Connection for status checks. Request a new URL when a new attempt
79
+ is needed, such as after expiry. On an already-connected site it is allowed: the
80
+ same Google account refreshes the credentials, a different one replaces the
81
+ connection. Say which before you do it.
82
+
83
+ 1. Read Get Connection. If `VALID`, stop unless the user wants to reconnect.
84
+ 2. Call [Get Connect URL](https://dev.wix.com/docs/api-reference/business-management/seo/google-search-console/connection-v1/get-connect-url). The request takes no parameters or body.
85
+
86
+ ```
87
+ GET https://www.wixapis.com/gsc/connection/v1/connect-url
88
+ ```
89
+
90
+ ```json
91
+ { "connectUrl": "https://accounts.google.com/o/oauth2/v2/auth?client_id=407408718192.apps.googleusercontent.com&redirect_uri=https%3A%2F%2Fwww.wixapis.com%2Fgsc%2Fconnection%2Fv1%2Fconnect-callback&response_type=code&scope=openid%20email%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fwebmasters&state=EXAMPLE_STATE" }
92
+ ```
93
+
94
+ The response above is illustrative. Wix generates the authorization URL,
95
+ including its OAuth query parameters. Give the user the exact returned
96
+ `connectUrl`; do not construct, modify, or reuse the example URL.
97
+
98
+ 3. Give the URL to the user and ask them to tell you when they have finished. Wix
99
+ completes the exchange server-side; there is no code to send back.
100
+ 4. When the user says they are done, read Get Connection once and confirm `VALID`.
101
+ Do not poll while waiting. If it is still `PENDING`, the user has not finished;
102
+ if the attempt expired (two hours), request a fresh URL only after they agree.
103
+
104
+ ## Writes need a published, indexable site with a connected domain
105
+
106
+ Get Connect URL, Verify Site, Add Site, and Submit Sitemap fail with
107
+ `FAILED_PRECONDITION` until the site is published, has a connected (premium)
108
+ domain, and allows indexing. The code names the first failing check:
109
+
110
+ ```json
111
+ { "message": "FAILED_PRECONDITION: The site has no connected domain. Connect a domain before connecting the site to Google Search Console",
112
+ "details": { "applicationError": { "code": "DOMAIN_NOT_CONNECTED" } } }
113
+ ```
114
+
115
+ Codes: `SITE_NOT_PUBLISHED`, `DOMAIN_NOT_CONNECTED`, `SITE_NOT_INDEXABLE`. A free
116
+ site on a `wixsite.com` address cannot complete these writes. Report the missing
117
+ prerequisite and stop. When listing sites to find one that qualifies, filter for
118
+ premium sites with a connected domain.
119
+
120
+ ## Set the site up in Search Console
121
+
122
+ Run the steps the user asked for, in this order, confirming before each write.
123
+ Bodies are empty unless shown.
124
+
125
+ | Step | Call | Notes |
126
+ |---|---|---|
127
+ | Verify ownership | `POST /gsc/v1/verify-site` with `{ "method": "META" }` | Synchronous against Google, allow up to 60 s. Idempotent. Wix already places the meta tag. |
128
+ | Add the property | `POST /gsc/v1/add-site` | Requires a verified site. |
129
+ | Submit the sitemap | `POST /gsc/v1/submit-sitemap` | Wix hosts and generates the sitemap. Google processes it asynchronously. |
130
+ | Request indexing | `POST /gsc/v1/request-site-indexing` | Success means Google accepted the request, not that the site is indexed. |
131
+ | Request one page | `POST /gsc/v1/request-page-indexing` with `{ "url": "https://www.example.com/about" }` | Full URL of a page on this site. |
132
+
133
+ All succeed with `{}`. Re-read Get Site Readiness after each step and act on the
134
+ current `blockingReason`. Verify Site on an already-verified site returns `{}` and
135
+ re-stamps the `SITE_VERIFIED` event date: safe, but not a change to report.
136
+
137
+ Two Google-side failures are retryable. `RESOURCE_EXHAUSTED` (`GOOGLE_QUOTA_EXCEEDED`):
138
+ the quota is daily, tell the user to retry tomorrow. `UNAVAILABLE`
139
+ (`GOOGLE_UNAVAILABLE`): retry once after a few seconds. On any other error your next
140
+ message is the final response: name the step that failed and the error code, and
141
+ make no further Search Console calls.
142
+
143
+ ## Check what was done: List Events and List Sitemaps
144
+
145
+ ```
146
+ GET https://www.wixapis.com/gsc/v1/events
147
+ ```
148
+
149
+ ```json
150
+ { "events": [
151
+ { "eventType": "ACCOUNT_CONNECTED", "occurredDate": "2025-10-29T11:10:15.869Z" },
152
+ { "eventType": "SITE_VERIFIED", "occurredDate": "2026-09-07T11:39:31.992Z" },
153
+ { "eventType": "SITE_ADDED", "occurredDate": "2025-10-29T11:07:39.050Z" } ] }
154
+ ```
155
+
156
+ One entry per event type with the date it **last** occurred, **not sorted by
157
+ date**: never read the last entry as the latest event. Types: `ACCOUNT_CONNECTED`,
158
+ `SITE_VERIFIED`, `SITE_ADDED`, `SITEMAP_SUBMITTED`, `SITE_INDEXING_REQUESTED`,
159
+ `PAGE_INDEXING_REQUESTED`. A missing type means that step never happened.
160
+
161
+ ```
162
+ GET https://www.wixapis.com/gsc/v1/sitemaps
163
+ ```
164
+
165
+ ```json
166
+ { "sitemaps": [ { "url": "https://www.example.com/blog-posts-sitemap.xml", "type": "sitemap", "pending": false,
167
+ "lastDownloadedDate": "2026-09-05T15:14:47.210Z", "errorCount": "0", "warningCount": "0",
168
+ "contents": [ { "type": "web", "submittedCount": "1", "indexedCount": "1" } ] } ] }
169
+ ```
170
+
171
+ Wix submits several sitemaps, typically one per content type. `pending: true` with
172
+ an empty `type` means Google has not processed it yet. Counts are strings.
173
+
174
+ ## Read search performance
175
+
176
+ ```
177
+ GET https://www.wixapis.com/gsc/v1/search-analytics?startDate=2026-08-01&endDate=2026-08-31&dimensions=query&rowLimit=5
178
+ ```
179
+
180
+ ```json
181
+ { "results": [ { "keys": ["best of santorini"], "clicks": 0, "impressions": 3, "ctr": 0, "position": 36 } ] }
182
+ ```
183
+
184
+ - `startDate` and `endDate` are required, `YYYY-MM-DD`, end inclusive.
185
+ - `dimensions` repeats: `date`, `query`, `page`, `country`, `device`,
186
+ `searchAppearance`; omit for one aggregate row. `keys` follow your order.
187
+ - `type`: `web` (default), `image`, `video`, `news`. Page with `rowLimit`/`startRow`.
188
+ - It is Google's own report: the latest days are usually missing, and there is no
189
+ history from before the property was added. Empty `results` is a real answer.
190
+
191
+ ## Inspect pages
192
+
193
+ Page IDs are Wix static-page IDs, not URLs. Discover them with
194
+ [List Item SEO Tags](https://dev.wix.com/docs/api-reference/business-management/seo/item-seo-tags-v1/list-item-seo-tags)
195
+ for `STATIC_PAGE`. The request has no body:
196
+
197
+ ```
198
+ GET https://www.wixapis.com/promote/seo/v1/item-seo-tags/STATIC_PAGE
199
+ ```
200
+
201
+ Relevant response fields (unrelated SEO fields omitted; IDs are illustrative):
202
+
203
+ ```json
204
+ { "itemSeoTags": [ { "id": "STATIC_PAGE:c1dmp", "itemType": "STATIC_PAGE", "itemId": "c1dmp" } ],
205
+ "pagingMetadata": { "count": 1, "hasNext": false, "cursors": {} } }
206
+ ```
207
+
208
+ If `pagingMetadata.hasNext` is `true`, pass `pagingMetadata.cursors.next` back as
209
+ `paging.cursor` in the next request's query string, URL-encoded. Continue until
210
+ `hasNext` is `false`. The optional `paging.limit` controls the page size; omit the
211
+ cursor on the first request. Treat cursors as opaque.
212
+
213
+ Use each selected entry's `itemId` as a `pageIds` entry for Inspect URLs. Do not
214
+ use the composite `id` (`STATIC_PAGE:c1dmp`) or a page URL, and never invent an ID.
215
+ The example below assumes discovery returned `c1dmp` for the selected page.
216
+
217
+ ```
218
+ POST https://www.wixapis.com/gsc/v1/inspect-urls
219
+ ```
220
+
221
+ ```json
222
+ { "pageIds": ["c1dmp"], "updateResults": true }
223
+ ```
224
+
225
+ ```json
226
+ { "results": [ { "page": { "pageId": "c1dmp", "name": "Home", "path": "/", "itemType": "STATIC_PAGE" },
227
+ "status": "OK", "createdDate": "2026-09-07T12:09:55.301Z",
228
+ "data": { "inspectionResultLink": "https://search.google.com/search-console/inspect?resource_id=https%3A%2F%2Fwww.example.com%2F&id=EXAMPLE_INSPECTION_ID",
229
+ "indexStatusResult": { "verdict": "PASS", "coverageState": "Submitted and indexed",
230
+ "indexingState": "INDEXING_ALLOWED", "lastCrawlTime": "2026-08-16T11:39:45Z",
231
+ "googleCanonical": "https://www.example.com/", "userCanonical": "https://www.example.com/" } } } ],
232
+ "status": "COMPLETE", "remainingPageCount": 0 }
233
+ ```
234
+
235
+ - `data.inspectionResultLink` is returned by Google. The complete URL above is
236
+ illustrative; use the actual returned link unchanged, including its query
237
+ parameters. Do not construct a link from the example values.
238
+ - Each page spends one unit of the account's Google quota (2,000 per property per
239
+ day): confirm the page list first. Sites over 2,000 pages fail with
240
+ `SITE_EXCEEDS_INSPECTION_LIMIT`.
241
+ - The site stores **one** inspection; without `updateResults: true` a new call
242
+ replaces it. Prefer `true` unless the user wants a clean run.
243
+ - `ONGOING`: poll `GET https://www.wixapis.com/gsc/v1/inspection` every few
244
+ seconds until `COMPLETE` or `ERROR` (same shape plus `updatedDate`).
245
+ - `remainingPageCount > 0` on `COMPLETE` means quota ran out. Name the missing
246
+ pages; do not call it done.
247
+ - `data` is Google's raw URL Inspection payload: read `indexStatusResult.verdict`
248
+ (`PASS`, `PARTIAL`, `FAIL`, `NEUTRAL`) and `coverageState`; text is English only.
249
+ `UNKNOWN_INSPECTION_STATUS` with empty `results` means never inspected.
250
+
251
+ ## Disconnect and clear
252
+
253
+ Two different removals; confirm which one the user wants.
254
+
255
+ | Call | Removes | Keeps |
256
+ |---|---|---|
257
+ | `POST /gsc/connection/v1/disconnect` | Stored Google credentials | Verification tag, Search Console property |
258
+ | `POST /gsc/v1/clear-verification` | Verification tag, verification state, **and** credentials | Search Console property |
259
+
260
+ Neither removes the site from Search Console or revokes Wix's access on Google's
261
+ side. Disconnect with no stored credentials returns `NOT_FOUND`
262
+ (`CONNECTION_NOT_FOUND`).
263
+
264
+ ## When a call fails
265
+
266
+ - `403` or `PERMISSION_DENIED`: stop after the first and report the missing SEO
267
+ permission (reads need view access to SEO settings, writes need manage access).
268
+ Do not try another site, path, or method.
269
+ - `FAILED_PRECONDITION`: act on `details.applicationError.code` as above. Do not
270
+ retry the same call.
271
+ - Get Connect URL is a recovery step only for `MISSING_TOKEN`, `INVALID`, or
272
+ `TOKEN_INVALID`, and only after the user agrees to reconnect.
@@ -0,0 +1,53 @@
1
+ ---
2
+ name: "Upload a Website or HTML Files"
3
+ description: Get a user's ready-made website live on Wix when they already have the site files — an index.html, a zip, or a static build exported from an AI builder or any other tool — by sending them to the Wix Headless drop page, where they upload the files and instantly get a live hosted site they can claim into their account. Use whenever the user wants to upload, publish, or host their own HTML/CSS/JS files as a NEW site. Not for migrating a live store/site from another platform by URL or from CSV exports (use Site Import), not for adding HTML or custom code into an existing Wix site, and not for uploading images or documents to a site's media files.
4
+ ---
5
+
6
+ # Upload a Website or HTML Files
7
+
8
+ The user already has a finished website as files — hand-written HTML, a zip
9
+ export, or the output of an AI site builder — and wants it live on Wix as a
10
+ new site. There is no API call to make. Send them to the upload page and
11
+ explain the flow:
12
+
13
+ ```
14
+ https://www.wix.com/headless/drop?utm_campaign=mcp
15
+ ```
16
+
17
+ **Always give the URL exactly as written above, including the
18
+ `utm_campaign=mcp` query parameter.** It attributes the visit to an
19
+ assistant/MCP referral; dropping or rewriting it breaks that attribution.
20
+
21
+ ## What happens on that page
22
+
23
+ 1. The user drags in their files (or a zip) — no login needed.
24
+ 2. Wix hosts them immediately on a live URL they can open and share.
25
+
26
+ ## Tell the user before they upload
27
+
28
+ Share the requirements that match their situation — these are the common
29
+ reasons an upload fails:
30
+
31
+ - The upload must contain an **HTML file at the top level of the site's
32
+ files**. It does not need to be named `index.html` — a single HTML file of
33
+ any name is served as the homepage — and a zip or folder that wraps
34
+ everything in one top-level folder (e.g. `my-site/index.html`) is unwrapped
35
+ automatically.
36
+ - Size limits: **3 MB per file, 20 MB total.**
37
+ - **Static files only** — HTML, CSS, JavaScript, and assets. If the user has
38
+ framework source code that needs a build step (a `package.json`, React/Vue
39
+ source, etc.), they must run their build first and upload the build output
40
+ folder's contents, not the source.
41
+
42
+ ## Route the request correctly
43
+
44
+ | The user has… | Do this |
45
+ |---|---|
46
+ | Site files on their machine (HTML/zip/AI-builder export), wants a new site | This recipe — send them to the drop URL above |
47
+ | A live site or store on another platform (a URL), or CSV/TSV exports, and wants content/products migrated | [Site Import](site-import.md) |
48
+ | An existing Wix site they want to add HTML, an embed, or custom code into | Not this recipe — that's embedding custom code in the site editor |
49
+ | Images, videos, or documents to add to a site | [Upload Media to Wix](../media/upload-media-to-wix.md) — media goes to the site's media files, not a new site |
50
+
51
+ Do not try to perform the upload for the user through an API, and do not
52
+ create a site for them with other site-creation tools instead — the drop page
53
+ is the flow.
@@ -5,6 +5,6 @@ description: "Changes the store's payment currency through Site Properties and e
5
5
 
6
6
  # Change Store Currency
7
7
 
8
- Use the [Site Properties currency recipe](https://dev.wix.com/docs/api-reference/business-management/site-properties/skills/change-payment-currency-site-properties.md) to set the requested payment currency and read it back. Confirm the change with the user before updating it.
8
+ Use the [Change a Site's Regional Properties (Currency, Time Zone, Language) via Site Properties API](../site-properties/change-payment-currency-site-properties.md) recipe to set the requested payment currency and read it back. Confirm the change with the user before updating it.
9
9
 
10
10
  Catalog product responses may temporarily show the previous currency after carts and checkout use the new one. Allow time for propagation, then recheck.
@@ -100,7 +100,9 @@ product **without** `imageUrl` and attach it afterwards with `attachProductImage
100
100
 
101
101
  ## STEP 4 — Wrap up
102
102
 
103
- ### Preview
103
+ ### Verify
104
+
105
+ Verify **once, after the seed** — home, shop, and a product page against the populated catalog.
104
106
 
105
107
  Images that are still generating may show `/__generating__/…` placeholders;
106
108
  the platform replaces these automatically at turn end, with a stock fallback if generation
@@ -85,7 +85,9 @@ product **without** `imageUrl` and attach it afterwards with `attachProductImage
85
85
 
86
86
  ## STEP 3 — Wrap up
87
87
 
88
- ### Preview
88
+ ### Verify
89
+
90
+ Verify **once, after the seed** — home, shop, and a product page against the populated catalog.
89
91
 
90
92
  Images that are still generating may show `/__generating__/…` placeholders;
91
93
  the platform replaces these automatically at turn end, with a stock fallback if generation
@@ -62,7 +62,7 @@ need to diagnose and fix it.
62
62
 
63
63
  **No seeding in this flow** — the client is the only deliverable. Do not seed, populate, or write data to Wix.
64
64
 
65
- ### Preview
65
+ ### Verify
66
66
 
67
67
  Images that are still generating may show `/__generating__/…` placeholders;
68
68
  the platform replaces these automatically at turn end, with a stock fallback if generation
@@ -9,7 +9,7 @@ or configuration changes are needed to build the UI. Never mock products or hand
9
9
  `/checkout` URL; the shipped cart uses the eCom redirect session.
10
10
 
11
11
  ## Prerequisites
12
- - The site's **Wix Stores** catalog is the read/cart target. It's installed and seeded separately, in parallel with this build — so it may be empty at build time; render the empty state until products land.
12
+ - The site's **Wix Stores** catalog is the read/cart target. It may be empty while the client is being built — render the empty state cleanly. Flows that seed do so after the client is built; verify the storefront once the catalog is populated, not against the empty state.
13
13
 
14
14
  ## Already installed in `src/`
15
15
  Successful deployment verified these files are in place; use this map without needing to read their source (`@/` → `src/`).
@@ -1,80 +0,0 @@
1
- # Collection Toolkit — what to reach for, per user need
2
-
3
- [UX_SUCCESS_MODEL.md](UX_SUCCESS_MODEL.md) says what a dashboard must do for the person using it. This file says which component does it, so the stage list resolves to real names instead of a hand-rolled approximation.
4
-
5
- Everything below is a real name in the installed `@wix/patterns`. Confirm the props before writing JSX by reading its doc from `dist/docs/index.json` — and if a name is missing from `dist/dts-bundle/index.json`, the installed version is older than this file; work from that inventory, not from memory.
6
-
7
- > **The two requirements below are not suggestions.** A page that renders a filtered table and nothing else is the single most common failure of a generated dashboard: it answers "what are all the records" and nothing about how many, which one needs attention, or why something happened. Measured runs produce exactly that page unless the requirement is stated.
8
- >
9
- > 1. **A dashboard that reports on records shows aggregate numbers**, not only rows.
10
- > 2. **A dashboard whose rows represent real business records lets the user open one**, unless the prompt is explicitly a report or an export.
11
-
12
- ## Understand — the aggregate
13
-
14
- | Need | Component |
15
- | --- | --- |
16
- | Totals, counts, status breakdown above the table | `SummaryBar` |
17
- | Which subset the numbers describe | wire each metric to the collection's filter state so the count follows the filters |
18
-
19
- `SummaryBar` sits inside the page shell, above the collection. Compute the values from the same query the table uses, or a count query alongside it — a metric that disagrees with the visible rows is worse than no metric.
20
-
21
- ## Focus — narrowing
22
-
23
- | Need | Component |
24
- | --- | --- |
25
- | Free-text search | `CollectionSearch` |
26
- | The filter bar itself | `CollectionToolbarFilters` |
27
- | Pick several values from a known list | `MultiSelectCheckboxFilter`, `MultiInlineCheckboxFilter`, `MultiAutoInlineCheckboxFilter` |
28
- | Pick one value | `SingleSelectFilter`, `RadioGroupFilter`, `TabsFilter` |
29
- | Values fetched from an API, not a fixed list | `MultiSelectCollectionFilter` + `useFilterCollection` |
30
- | Type-ahead over many values | `AutoCompleteFilter` |
31
- | Date or number ranges | `DateRangeFilter`, `NumberRangeFilter` |
32
- | Comparison operators (greater than, contains) | `OperatorFilterPicker` + `operatorFilter` |
33
- | The filter's state object | `idNameArrayFilter`, `stringFilter`, `stringsArrayFilter`, `arrayFilter`, `dateRangeFilter`, `customFilter` |
34
- | A fixed in-memory option list for a filter | `useStaticListFilterCollection` |
35
- | Sorting | `Sortable Columns`, `MultiLevelSorting` |
36
-
37
- **Read the index once, then go straight to files.** `dist/dts-bundle/index.json` answers every name in this table in a single read — resolve it once per session and keep it, rather than re-reading it per lookup. Each entry names the exact file to open next.
38
-
39
- **A factory or hook's doc is often empty where its signature should be** — the props table is generated for components, so `idNameArrayFilter`'s doc shows an `## API` heading with nothing under it. Its bundle has the signature: `<T extends { id: string; name: string }>(params?) => ArrayFilterState<T>`. That holds for every `use…` hook and every `…Filter` factory in the table above, and it is the difference between knowing a name and being able to call it — so for these, read the bundle the index names, not the doc.
40
-
41
- **A filter must narrow the result.** Declare it in the collection hook's `filters` map and read it inside `fetchData`, so the value reaches the query. Filter UI that renders but never changes the rows is a defect that looks like a feature — and it is the failure mode these components exist to prevent.
42
-
43
- ## Investigate — opening one record
44
-
45
- | Surface | Use when | Built from |
46
- | --- | --- | --- |
47
- | **Side panel** | Inspect or lightly edit one record while keeping the filtered list on screen. The V1 default for review dashboards. | WDS `SidePanel` — patterns has no side panel |
48
- | **Entity page** | Multi-section detail, editing, history, or a link someone can share. | `EntityPage` + `useEntityPage`, reached with `usePatternsNavigate().navigateToEntityPage`, form state from `@wix/patterns/form`. The call itself: [ENTITY_PAGE_TOOLKIT.md](ENTITY_PAGE_TOOLKIT.md) |
49
- | **Expanded row** | A couple of extra fields, no separate workspace needed. | The collection's own row expansion |
50
- | **Picker / bulk confirm** | Choosing records, or confirming an action on many. | `PickerModal` + `usePickerModal`, `bulkActionModal` |
51
-
52
- A dialog that creates, updates or displays one listed record is **not** a dashboard modal — a create / "add new" form included, since it writes the record. See [DASHBOARD_MODAL.md](../DASHBOARD_MODAL.md); for the create route itself — registering it, and the four params that differ from the edit call — [ENTITY_PAGE_TOOLKIT.md § Create route](ENTITY_PAGE_TOOLKIT.md#create-route). A row the user cannot open is the second most common failure after the missing aggregate.
53
-
54
- **Form state on an entity page** comes from `@wix/patterns/form` — `useForm` for the form, `useController` for a single field. That subpath re-exports `@wix/bex-core/form`, which wraps `react-hook-form`, so its API is react-hook-form's and only a handful of its names appear in the patterns docs: `FieldValues`, `ControllerProps` and most of the rest are documented by react-hook-form, not here. `Read <pkgRoot>/dist/dts-bundle/exports/form.d.ts` to see what the subpath actually gives you.
55
-
56
- ## Act and confirm
57
-
58
- | Need | Component |
59
- | --- | --- |
60
- | Page header actions | `PrimaryActions`, `SecondaryActions`, `More Actions` — passed to the page header's `primaryAction`, `secondaryActions` and `moreActions` slots |
61
- | Table toolbar button | `PrimaryActionButton` — the table's own `primaryActionButton` prop |
62
- | Row actions | `deleteSecondaryAction`, in the row's `actionCell` |
63
- | Acting on a multi-row selection | `MultiBulkActionToolbar`, `bulkActionModal` |
64
- | Immediate feedback, then reconcile | `useOptimisticActions(state.collection)` ✅ — not `useOptimisticActions(state)` ❌: `useTableCollection()` returns `TableState<T, F>`, and the hook takes the `CollectionState<T, F>` that state exposes as `state.collection`. Returns `CollectionOptimisticActions` |
65
- | A banner above the table | `TableTopNotification` |
66
-
67
- ## The states that are not the happy path
68
-
69
- | State | Component |
70
- | --- | --- |
71
- | Collection is genuinely empty | `CollectionEmptyState` |
72
- | Filters or search matched nothing | `CollectionNoResultsState` |
73
- | Feature needs a paid plan | `CollectionPremiumEmptyState` |
74
- | Load failed | the collection state's error handling — give the user a way to retry |
75
-
76
- Empty and no-results are different messages: one means "add your first record", the other means "loosen the filters". Shipping only the first makes a working filter look broken.
77
-
78
- ## Export
79
-
80
- `ExportButton` (its doc is `ExportTo`) for CSV and similar. Reach for it when the prompt mentions exporting, downloading, or sending records elsewhere.
@@ -1,140 +0,0 @@
1
- # Entity Page Toolkit — calling `useEntityPage`
2
-
3
- [COLLECTION_TOOLKIT.md](COLLECTION_TOOLKIT.md) says a row the user cannot open is a defect, and sends you to `EntityPage` + `useEntityPage` to fix it. This file is the call itself.
4
-
5
- ## The call
6
-
7
- ```tsx
8
- import { useEntityPage, EntityPage } from '@wix/patterns';
9
- import { useForm } from '@wix/patterns/form';
10
-
11
- interface Shift {
12
- id?: string;
13
- name?: string;
14
- }
15
-
16
- interface ShiftFormFields {
17
- name?: string;
18
- }
19
-
20
- const form = useForm<ShiftFormFields>({ defaultValues: { name: '' } });
21
-
22
- const state = useEntityPage<Shift, ShiftFormFields>({
23
- fetch: () => api.getShift(shiftId).then((entity) => ({ entity })),
24
- onSave: ({ widgetsFormData }) =>
25
- api
26
- .updateShift(shiftId, { ...form.getValues(), ...widgetsFormData })
27
- .then((updatedEntity) => ({ updatedEntity })),
28
- form,
29
- parentPath: '/',
30
- });
31
- ```
32
-
33
- **`parentPath` is relative to the router's own mount point — the dashboard page's
34
- own root, not the page's `route` value.** A dashboard page scaffolded with
35
- `{"route": "shifts"}` is served at `/dashboard/shifts`, but `PatternsReactRouter`
36
- still sees its own location start fresh at `/` inside that page — so `parentPath`,
37
- every `PatternsReactRoute`'s `path`, and the `path` passed to
38
- `navigateToEntityPage()` / `navigateToCollectionPage()` must never repeat the
39
- page's own `route`/name. `parentPath: '/shifts'` on a page whose `route` is
40
- `"shifts"` is the single most common way this gets copied wrong — it looks like a
41
- reasonable guess (name the parent after the page) and compiles, but the
42
- collection route it points back to is registered at `path="/"`, not
43
- `path="/shifts"`, so `parentPath` must match that: `'/'`. See [Create
44
- route](#create-route) below for the full route registration.
45
-
46
- From **1.465.0** the library's own docs state this rule — `PatternsReactRouter.md`,
47
- `usePatternsNavigate.md` and `useEntityPage.md`'s **Create route**. On an older
48
- install they don't, and their examples *demonstrate* the mistake
49
- (`navigateToEntityPage({ path: '/shifts/new' })`, `navigateToCollectionPage({ path:
50
- '/entities' })`); prefer this rule over what those examples show.
51
-
52
- `EntityPage` and `useEntityPage` are **root** exports. `@wix/patterns/page` holds `CollectionPage` and `WidgetsFormProvider` only, so importing the entity page from there is `TS2305: has no exported member` — the collection page and the entity page do not live in the same place. `Read <pkgRoot>/dist/dts-bundle/exports/page.d.ts` to see what that subpath actually gives you.
53
-
54
- ## Name both generics
55
-
56
- `useEntityPage<T, V extends FieldValues = FieldValues>` takes the entity type **and** the form-values type. `V` does not infer from the `form` argument — it falls back to `FieldValues`, and a `useForm<ShiftFormFields>()` then fails to assign with `Type 'UseFormReturn<ShiftFormFields, …>' is not assignable to type 'UseFormReturn<FieldValues>'`. Naming a single generic only works when the form is untyped.
57
-
58
- `useEntityPage<any, ShiftFormFields>` makes that error go away and takes the entity type with it — `state.entity` becomes `any`, and every field access below it stops being checked. Name the entity type.
59
-
60
- ## `onSave` does not hand you the form values
61
-
62
- `OnSaveParams` has exactly one key. `widgetsFormData` carries what the **widget** fields contributed — extended fields, tags — not what the user typed into your own fields. Those come from the form you already own:
63
-
64
- ```tsx
65
- onSave: ({ widgetsFormData }) => {
66
- const values = form.getValues(); // your fields
67
- const { extendedFields, tags } = widgetsFormData; // widget fields
68
- …
69
- };
70
- ```
71
-
72
- Reaching for a `values`-shaped key on the `onSave` argument is the usual first guess, and there isn't one.
73
-
74
- ## The params are a `Pick`
75
-
76
- `UseEntityPageParams` picks a fixed set off `EntityPageStateParams` — `fetch`, `onSave`, `saveSuccessToast`, `saveErrorToast`, `deleteAction`, `transformEntityToCollectionItem`, `isNewEntity` (create vs edit — [Create route](#create-route)), `form`, `parentPageId`, `parentPath`, `parentReferrer`, `schemaSource`. Anything outside that list is an excess-property error on the object literal. `container` is the common guess and is not one of them: the hook calls `useWixPatternsContainer()` itself.
77
-
78
- Confirm the shape rather than guessing — the hook's doc ends by pointing at the bundle rather than tabulating props, because props tables only exist for components. `Read <pkgRoot>/dist/dts-bundle/index.json`, then `Read` the bundled `.d.ts` for each of `useEntityPage`, `UseEntityPageParams`, and `OnSaveParams` at exactly the `file` path the index gives.
79
-
80
- ## Create route
81
-
82
- The example above is edit-only. "Add new" is an `EntityPage` too, and it is not the same call with the id left out. Four things differ, and three of them fail silently if you guess:
83
-
84
- - The route is its own `PatternsReactRoute type="createEntity"`. One component can serve both entity routes; the route is what tells them apart.
85
- - `navigateToEntityPage({ path })` — omit `entity`. It exists so the header can render a title before the fetch resolves, and a create route has no record to give it. A placeholder is worse than nothing: until `fetch` resolves it *is* `state.entity`.
86
- - `fetch` is required on the create route too, and `{ entity: undefined }` is the create case built into its return type — not a loading state, and there is no `fetch`-less variant.
87
- - `isNewEntity` is the only param that tells the page which route it is on. Omitted, a create page that seeds defaults through `fetch` is announced to the collection as an *update*: the collection changes a row it does not have, the new record never appears in the list, and the only trace is a `Fetched page info for updated entity not found` console error.
88
-
89
- `Read <pkgRoot>/dist/docs/useEntityPage.md` before writing one — its **Create route** section carries the worked component that serves both routes off one `useParams` answer, and the `boolean | (() => boolean)` getter form for `isNewEntity`.
90
-
91
- **If that file has no `Create route` heading, the installed `@wix/patterns` predates 1.464.0.** Upgrade and re-read rather than working around it: on those versions `navigateToEntityPage` types `entity` as required, so omitting it does not compile, and passing the placeholder that satisfies it is the failure the bullet above describes.
92
-
93
- ## Around the call
94
-
95
- | Step | What owns it |
96
- | --- | --- |
97
- | Getting here from the collection page | `usePatternsNavigate()` → `navigateToEntityPage({ path, entity })` |
98
- | Registering the route | `PatternsReactRoute` inside `PatternsReactRouter` |
99
- | Form state and field binding | `useForm` / `useController` from `@wix/patterns/form` — `useController`, never `register` |
100
- | Body layout | `EntityPage.Header`, `.MainContent`, `.AdditionalContent`, `.Card` |
101
- | The fields inside those cards | `@wix/design-system` (`FormField`, `Input`, `Text`) |
102
-
103
- Every `path` in that first row — the route's own `path`, `parentPath`, and the `path` argument to `navigateToEntityPage`/`navigateToCollectionPage` — is relative to the page's own root, never to its `route`/name. See the `parentPath` note under [The call](#the-call) above; it is the same rule everywhere a path appears in this table.
104
-
105
- `@wix/patterns/form` re-exports `@wix/bex-core/form`, which wraps `react-hook-form` — so `form.getValues()`, `form.reset()` and the rest are react-hook-form's API, documented there rather than in the patterns docs.
106
-
107
- ## Binding a field: `useController`, never `register`
108
-
109
- `register` returns props for a plain `<input>`, and WDS components are not one. Two ways it fails:
110
-
111
- `<Input {...register('qty')} />` does not compile — `register` always returns `min`/`max` as `string | number`, whatever options you passed, and WDS types them `number | undefined`. The error names `InputProps`, which reads like a WDS bug and isn't.
112
-
113
- `<Input ref={register('qty').ref} />` **does** compile and is wrong. `Input`'s `ref` is its imperative handle (`Ref<InputImperativeActions>`); `register`'s ref is `(instance: any) => void`, so it accepts that and binds the handle rather than the `<input>`. The field never registers, validation never sees it, and nothing reports it.
114
-
115
- Bind through value/onChange instead:
116
-
117
- ```tsx
118
- import { useController, useForm } from '@wix/patterns/form';
119
- import { FormField, Input } from '@wix/design-system';
120
-
121
- type ProductForm = { name: string; qty: number };
122
-
123
- function NameField({ form }: { form: ReturnType<typeof useForm<ProductForm>> }) {
124
- const { field, fieldState } = useController({
125
- name: 'name',
126
- control: form.control,
127
- rules: { required: 'Name is required' },
128
- });
129
-
130
- return (
131
- <FormField label="Name" required status={fieldState.error ? 'error' : undefined} statusMessage={fieldState.error?.message}>
132
- <Input value={field.value} onChange={field.onChange} onBlur={field.onBlur} />
133
- </FormField>
134
- );
135
- }
136
- ```
137
-
138
- Rules live in `rules`, not on the WDS component. If you need `register` for a DOM concern such as input masking, `Input` takes `inputRef?: React.Ref<HTMLInputElement>` — pass the ref there, never to `ref`.
139
-
140
- A dialog that creates, updates or displays one listed record is **not** a dashboard modal — a create / "add new" form included, since it writes the record. See [DASHBOARD_MODAL.md](../DASHBOARD_MODAL.md).