@wix/himalaya-cli 0.1222.0 → 0.1224.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.
Files changed (58) hide show
  1. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/events/src/display.d.ts +3 -0
  2. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-events.mjs +3 -1
  3. package/dist/cli.mjs +33 -24
  4. package/dist/preview-assets.generated.bin +0 -0
  5. package/guides/sdk-reference.json +1 -1
  6. package/package.json +2 -2
  7. package/templates/beauty-salon/dev/index.ts +5 -1
  8. package/templates/beauty-salon/tier5-src/_shared/collection-contract.ts +15 -2
  9. package/templates/beauty-salon/tier5-src/wix-spaces-create-post/index.ts +14 -4
  10. package/templates/beauty-salon-owner/tier5-src/_shared/collection-contract.ts +15 -2
  11. package/templates/branded-lite/dev/index.ts +520 -274
  12. package/templates/branded-lite/tier5-src/_shared/collection-contract.ts +15 -2
  13. package/templates/branded-lite/tier5-src/wix-spaces-create-post/index.ts +14 -4
  14. package/templates/community-club/dev/index.ts +518 -272
  15. package/templates/community-club/tier5-src/_shared/collection-contract.ts +15 -2
  16. package/templates/community-club/tier5-src/wix-spaces-create-post/index.ts +14 -4
  17. package/templates/community-club-owner/tier5-src/_shared/collection-contract.ts +15 -2
  18. package/templates/community-club-owner/tier5-src/himi-owner-lite-events/index.ts +1 -0
  19. package/templates/events-meetups/dev/index.ts +518 -272
  20. package/templates/events-meetups/tier5-src/_shared/collection-contract.ts +15 -2
  21. package/templates/events-meetups/tier5-src/wix-spaces-create-post/index.ts +14 -4
  22. package/templates/events-meetups-owner/tier5-src/_shared/collection-contract.ts +15 -2
  23. package/templates/events-meetups-owner/tier5-src/himi-owner-lite-events/index.ts +1 -0
  24. package/templates/gym-fitness/dev/index.ts +520 -274
  25. package/templates/gym-fitness/tier5-src/_shared/collection-contract.ts +15 -2
  26. package/templates/gym-fitness/tier5-src/wix-spaces-create-post/index.ts +14 -4
  27. package/templates/gym-fitness-owner/tier5-src/_shared/collection-contract.ts +15 -2
  28. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-events/index.ts +1 -0
  29. package/templates/nonprofit-cause/dev/index.ts +518 -272
  30. package/templates/nonprofit-cause/tier5-src/_shared/collection-contract.ts +15 -2
  31. package/templates/nonprofit-cause/tier5-src/wix-spaces-create-post/index.ts +14 -4
  32. package/templates/nonprofit-cause-owner/tier5-src/_shared/collection-contract.ts +15 -2
  33. package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-events/index.ts +1 -0
  34. package/templates/owner-lite/tier5-src/_shared/collection-contract.ts +15 -2
  35. package/templates/owner-lite/tier5-src/himi-owner-lite-events/index.ts +1 -0
  36. package/templates/podcast-creator/dev/index.ts +518 -272
  37. package/templates/podcast-creator/tier5-src/_shared/collection-contract.ts +15 -2
  38. package/templates/podcast-creator/tier5-src/wix-spaces-create-post/index.ts +14 -4
  39. package/templates/podcast-creator-owner/tier5-src/_shared/collection-contract.ts +15 -2
  40. package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-events/index.ts +1 -0
  41. package/templates/portfolio-creative/dev/index.ts +520 -274
  42. package/templates/portfolio-creative/tier5-src/_shared/collection-contract.ts +15 -2
  43. package/templates/portfolio-creative/tier5-src/wix-spaces-create-post/index.ts +14 -4
  44. package/templates/portfolio-creative-owner/tier5-src/_shared/collection-contract.ts +15 -2
  45. package/templates/restaurant/dev/index.ts +518 -272
  46. package/templates/restaurant/tier5-src/_shared/collection-contract.ts +15 -2
  47. package/templates/restaurant/tier5-src/wix-spaces-create-post/index.ts +14 -4
  48. package/templates/restaurant-owner/tier5-src/_shared/collection-contract.ts +15 -2
  49. package/templates/restaurant-owner/tier5-src/himi-owner-lite-events/index.ts +1 -0
  50. package/templates/retail-store/dev/index.ts +5 -1
  51. package/templates/retail-store/tier5-src/_shared/collection-contract.ts +15 -2
  52. package/templates/retail-store/tier5-src/wix-spaces-create-post/index.ts +14 -4
  53. package/templates/retail-store-owner/tier5-src/_shared/collection-contract.ts +15 -2
  54. package/templates/yoga-studio/dev/index.ts +518 -272
  55. package/templates/yoga-studio/tier5-src/_shared/collection-contract.ts +15 -2
  56. package/templates/yoga-studio/tier5-src/wix-spaces-create-post/index.ts +14 -4
  57. package/templates/yoga-studio-owner/tier5-src/_shared/collection-contract.ts +15 -2
  58. package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-events/index.ts +1 -0
@@ -37,6 +37,13 @@ export interface CollectionConfig {
37
37
  * `screenId` opens that screen with the row id; without it the verb reuses the
38
38
  * row's own tap action (the detail screen that owns the verb). */
39
39
  primaryVerb?: { label: string; screenId?: string };
40
+ /** A TIME-BOUND entity (an event, a booking, a reservation): the boolean row field the
41
+ * DOMAIN sets once the record has finished — computed by the same rule as the row's own
42
+ * "Past" label, in the same place, so the two cannot disagree. A finished
43
+ * record's `primaryVerb` (Register, Book…) is transactional and would act on something
44
+ * that is over, so it is swapped for a non-transactional "View details" that opens the
45
+ * row's own detail. Without a row tap action the verb is simply hidden. */
46
+ endedWhen?: string;
40
47
  /** A catalog card whose one expected per-item action is "favorite".
41
48
  * The ellipsis overflow is replaced by an always-visible heart toggle wired to
42
49
  * the same `collectionSave` reducer. A dropdown `Menu` anchored inside a
@@ -57,7 +64,7 @@ export const COLLECTIONS: Record<string, CollectionConfig> = {
57
64
  himiBookingBookings: { rows: 'rows', title: 'title', subtitle: 'subtitle', metadata: ['status'], view: 'list', backendQuery: true,
58
65
  defaultFilter: 'value:Upcoming', searchPlaceholder: 'Search by booking ID', countNoun: ['booking', 'bookings'], filterValues: ['Upcoming', 'Past', 'Cancelled'],
59
66
  sortLabels: { default: 'Soonest', az: 'Oldest', za: 'Latest' } },
60
- himiEvents: { rows: 'results', title: 'title', subtitle: 'dateLine', image: 'image', view: 'grid', backendQuery: true, defaultFilter: 'value:Upcoming', searchPlaceholder: 'Search events', countNoun: ['event', 'events'], filterValues: ['Upcoming', 'Past'], sortLabels: { default: 'Date', az: 'Title A–Z', za: 'Title Z–A' }, primaryVerb: { label: 'Register' } },
67
+ himiEvents: { rows: 'results', title: 'title', subtitle: 'dateLine', image: 'image', view: 'grid', backendQuery: true, defaultFilter: 'value:Upcoming', searchPlaceholder: 'Search events', countNoun: ['event', 'events'], filterValues: ['Upcoming', 'Past'], sortLabels: { default: 'Date', az: 'Title A–Z', za: 'Title Z–A' }, primaryVerb: { label: 'Register' }, endedWhen: 'isPast' },
61
68
  himiBlogFeed: { rows: 'posts', title: 'title', subtitle: 'excerpt', image: 'image', filter: 'category', filterValuesFrom: 'categories', view: 'grid', narrowedBy: 'selectedCategoryId' },
62
69
  himiOwnerLiteProducts: { rows: 'products', title: 'name', subtitle: 'price', image: 'image', view: 'grid', backendQuery: true, countNoun: ['product', 'products'] },
63
70
  himiOwnerModules: { instanceInput: 'module', rows: 'rows', title: 'title', subtitle: 'subtitle', image: 'image', filter: 'statusLabel', view: 'list', paged: true, reviewAction: 'prepareRecord', reviewSelectedAction: 'prepareSelected' },
@@ -180,7 +187,13 @@ export function projectCollection(source: CollectionRow[], config: CollectionCon
180
187
  collectionSubtitle: scalar(row[config.subtitle ?? '']) || scalar(row.subtitle) || scalar(row.description) || scalar(row.meta),
181
188
  collectionImage: scalar(row[config.image ?? '']), collectionNoImage: !scalar(row[config.image ?? '']), collectionHasImage: !!scalar(row[config.image ?? '']),
182
189
  collectionSaved: prefs.savedIds.includes(collectionId(row)), collectionNotSaved: !prefs.savedIds.includes(collectionId(row)), collectionSelected: prefs.selectedIds.includes(collectionId(row)),
183
- collectionNoIdentity: !collectionId(row) })),
190
+ collectionNoIdentity: !collectionId(row),
191
+ // Older cached EventRows predate `isPast` but already stored `statusLabel: "Past"`.
192
+ // Keep their ended state through an offline render until the row is refreshed.
193
+ ...(config.endedWhen ? (() => {
194
+ const ended = row[config.endedWhen] === true || (config.endedWhen === 'isPast' && row.statusLabel === 'Past');
195
+ return { collectionEnded: ended, collectionNotEnded: !ended };
196
+ })() : {}) })),
184
197
  filters, loaded: rows.length,
185
198
  };
186
199
  }
@@ -2,7 +2,7 @@
2
2
  // Holds the typed title + body; submit creates AND publishes a real blog post via
3
3
  // the Wix Blog API, then the new post shows up in ws_blog. (Forum has no member
4
4
  // create endpoint in the SDK; blog is the available authored-content write.)
5
- import { defineService } from "@himalaya/state";
5
+ import { defineService, navigate } from "@himalaya/state";
6
6
  import { createDraftPost, publishDraftPost } from "@himalaya/wix-blog";
7
7
  import { memberAccess } from "../_shared/member-access.js";
8
8
 
@@ -38,7 +38,7 @@ function val(arg?: unknown): string {
38
38
  return typeof arg === "string" ? arg : ((arg as { value?: string; text?: string })?.value ?? (arg as { text?: string })?.text ?? "");
39
39
  }
40
40
 
41
- const svc = defineService<S, { load: (s: S) => Promise<S>; setTitle: (s: S, a?: unknown) => S; setBody: (s: S, a?: unknown) => S; focusBody: (s: S) => S; submit: (s: S) => Promise<S> }>("spacesCreatePost", {
41
+ const svc = defineService<S, { load: (s: S) => Promise<S>; setTitle: (s: S, a?: unknown) => S; setBody: (s: S, a?: unknown) => S; focusBody: (s: S) => S; submit: (s: S, a?: unknown) => Promise<S> }>("spacesCreatePost", {
42
42
  state: { status: "ready", title: "", body: "", hint: "Share something with the community.", bodyFocus: "", needsSignIn: false, noSignIn: true, hideForm: true },
43
43
  actions: {
44
44
  load: async (s) => {
@@ -50,7 +50,11 @@ const svc = defineService<S, { load: (s: S) => Promise<S>; setTitle: (s: S, a?:
50
50
  // Title's Next key lands here. The keyboard stays up (that is the "next"
51
51
  // contract) and the body field takes focus.
52
52
  focusBody: (s) => ({ ...s, bodyFocus: bumpToken(s.bodyFocus) }),
53
- submit: async (s) => {
53
+ // `postScreenId` (a submit param) names the screen that shows ONE post, so a host
54
+ // with one lands the author on what they just posted. Several apps share this
55
+ // worker and each owns its own post screen, so the descriptor names it; without
56
+ // it the composer clears and confirms in place.
57
+ submit: async (s, a) => {
54
58
  if (s.needsSignIn) return { ...s, hint: "Sign in to post." };
55
59
  const title = s.title.trim();
56
60
  if (!title) return { ...s, hint: "Please enter a title." };
@@ -73,7 +77,13 @@ const svc = defineService<S, { load: (s: S) => Promise<S>; setTitle: (s: S, a?:
73
77
  // steals focus, so those transitions must clear it (see himi-store-account's
74
78
  // NO_FOCUS on its mode switches). Same token, opposite fix; the deciding
75
79
  // question is always whether the field stays mounted.
76
- return { ...s, status: "ready", title: "", body: "", bodyFocus: s.bodyFocus, hint: `Posted “${title}” ✓ — it now appears in Blog.` };
80
+ const posted: S = { ...s, status: "ready", title: "", body: "", bodyFocus: s.bodyFocus, hint: `Posted “${title}” ✓ — it now appears in Blog.` };
81
+ // Only after the worker has the post's id — a failure takes the catch below and
82
+ // keeps every character the user typed.
83
+ const postScreenId = (a as { postScreenId?: unknown } | undefined)?.postScreenId;
84
+ return id && typeof postScreenId === "string" && postScreenId
85
+ ? navigate(posted, { screenId: postScreenId, args: { id } })
86
+ : posted;
77
87
  } catch {
78
88
  return { ...s, status: "ready", hint: "Couldn't post — check your connection and try again." };
79
89
  } finally {
@@ -37,6 +37,13 @@ export interface CollectionConfig {
37
37
  * `screenId` opens that screen with the row id; without it the verb reuses the
38
38
  * row's own tap action (the detail screen that owns the verb). */
39
39
  primaryVerb?: { label: string; screenId?: string };
40
+ /** A TIME-BOUND entity (an event, a booking, a reservation): the boolean row field the
41
+ * DOMAIN sets once the record has finished — computed by the same rule as the row's own
42
+ * "Past" label, in the same place, so the two cannot disagree. A finished
43
+ * record's `primaryVerb` (Register, Book…) is transactional and would act on something
44
+ * that is over, so it is swapped for a non-transactional "View details" that opens the
45
+ * row's own detail. Without a row tap action the verb is simply hidden. */
46
+ endedWhen?: string;
40
47
  /** A catalog card whose one expected per-item action is "favorite".
41
48
  * The ellipsis overflow is replaced by an always-visible heart toggle wired to
42
49
  * the same `collectionSave` reducer. A dropdown `Menu` anchored inside a
@@ -57,7 +64,7 @@ export const COLLECTIONS: Record<string, CollectionConfig> = {
57
64
  himiBookingBookings: { rows: 'rows', title: 'title', subtitle: 'subtitle', metadata: ['status'], view: 'list', backendQuery: true,
58
65
  defaultFilter: 'value:Upcoming', searchPlaceholder: 'Search by booking ID', countNoun: ['booking', 'bookings'], filterValues: ['Upcoming', 'Past', 'Cancelled'],
59
66
  sortLabels: { default: 'Soonest', az: 'Oldest', za: 'Latest' } },
60
- himiEvents: { rows: 'results', title: 'title', subtitle: 'dateLine', image: 'image', view: 'grid', backendQuery: true, defaultFilter: 'value:Upcoming', searchPlaceholder: 'Search events', countNoun: ['event', 'events'], filterValues: ['Upcoming', 'Past'], sortLabels: { default: 'Date', az: 'Title A–Z', za: 'Title Z–A' }, primaryVerb: { label: 'Register' } },
67
+ himiEvents: { rows: 'results', title: 'title', subtitle: 'dateLine', image: 'image', view: 'grid', backendQuery: true, defaultFilter: 'value:Upcoming', searchPlaceholder: 'Search events', countNoun: ['event', 'events'], filterValues: ['Upcoming', 'Past'], sortLabels: { default: 'Date', az: 'Title A–Z', za: 'Title Z–A' }, primaryVerb: { label: 'Register' }, endedWhen: 'isPast' },
61
68
  himiBlogFeed: { rows: 'posts', title: 'title', subtitle: 'excerpt', image: 'image', filter: 'category', filterValuesFrom: 'categories', view: 'grid', narrowedBy: 'selectedCategoryId' },
62
69
  himiOwnerLiteProducts: { rows: 'products', title: 'name', subtitle: 'price', image: 'image', view: 'grid', backendQuery: true, countNoun: ['product', 'products'] },
63
70
  himiOwnerModules: { instanceInput: 'module', rows: 'rows', title: 'title', subtitle: 'subtitle', image: 'image', filter: 'statusLabel', view: 'list', paged: true, reviewAction: 'prepareRecord', reviewSelectedAction: 'prepareSelected' },
@@ -180,7 +187,13 @@ export function projectCollection(source: CollectionRow[], config: CollectionCon
180
187
  collectionSubtitle: scalar(row[config.subtitle ?? '']) || scalar(row.subtitle) || scalar(row.description) || scalar(row.meta),
181
188
  collectionImage: scalar(row[config.image ?? '']), collectionNoImage: !scalar(row[config.image ?? '']), collectionHasImage: !!scalar(row[config.image ?? '']),
182
189
  collectionSaved: prefs.savedIds.includes(collectionId(row)), collectionNotSaved: !prefs.savedIds.includes(collectionId(row)), collectionSelected: prefs.selectedIds.includes(collectionId(row)),
183
- collectionNoIdentity: !collectionId(row) })),
190
+ collectionNoIdentity: !collectionId(row),
191
+ // Older cached EventRows predate `isPast` but already stored `statusLabel: "Past"`.
192
+ // Keep their ended state through an offline render until the row is refreshed.
193
+ ...(config.endedWhen ? (() => {
194
+ const ended = row[config.endedWhen] === true || (config.endedWhen === 'isPast' && row.statusLabel === 'Past');
195
+ return { collectionEnded: ended, collectionNotEnded: !ended };
196
+ })() : {}) })),
184
197
  filters, loaded: rows.length,
185
198
  };
186
199
  }
@@ -96,6 +96,7 @@ function demoList(s: EventsState, upcoming = false): EventsState {
96
96
  location: d.location,
97
97
  status: d.statusLabel,
98
98
  statusLabel: "",
99
+ isPast: false,
99
100
  image: "",
100
101
  hasImage: false,
101
102
  noImage: true,