@wix/himalaya-cli 0.1593.0 → 0.1594.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 (24) hide show
  1. package/dist/cli.mjs +1 -0
  2. package/guides/one-app-to-himi-app.md +12 -0
  3. package/package.json +2 -2
  4. package/templates/beauty-salon/dev/index.ts +216 -8
  5. package/templates/beauty-salon/tier5-src/_shared/himi-store-facets.ts +26 -2
  6. package/templates/beauty-salon/tier5-src/himi-branded-lite-category/index.ts +3 -3
  7. package/templates/beauty-salon/tier5-src/himi-branded-lite-shop/index.ts +4 -4
  8. package/templates/branded-lite/dev/index.ts +216 -8
  9. package/templates/branded-lite/tier5-src/_shared/business-chat-transport.ts +9 -0
  10. package/templates/branded-lite/tier5-src/_shared/himi-store-facets.ts +26 -2
  11. package/templates/branded-lite/tier5-src/himi-branded-lite-category/index.ts +3 -3
  12. package/templates/branded-lite/tier5-src/himi-branded-lite-shop/index.ts +3 -3
  13. package/templates/gym-fitness/dev/index.ts +216 -8
  14. package/templates/gym-fitness/tier5-src/_shared/himi-store-facets.ts +26 -2
  15. package/templates/gym-fitness/tier5-src/himi-branded-lite-category/index.ts +3 -3
  16. package/templates/gym-fitness/tier5-src/himi-branded-lite-shop/index.ts +4 -4
  17. package/templates/portfolio-creative/dev/index.ts +216 -8
  18. package/templates/portfolio-creative/tier5-src/_shared/himi-store-facets.ts +26 -2
  19. package/templates/portfolio-creative/tier5-src/himi-branded-lite-category/index.ts +3 -3
  20. package/templates/portfolio-creative/tier5-src/himi-branded-lite-shop/index.ts +4 -4
  21. package/templates/retail-store/dev/index.ts +216 -8
  22. package/templates/retail-store/tier5-src/_shared/himi-store-facets.ts +26 -2
  23. package/templates/retail-store/tier5-src/himi-branded-lite-category/index.ts +3 -3
  24. package/templates/retail-store/tier5-src/himi-branded-lite-shop/index.ts +3 -3
@@ -10346,7 +10346,33 @@ const SCREENS = runtimeSetting({
10346
10346
  "top": 2,
10347
10347
  "bottom": 2
10348
10348
  },
10349
- "hiddenPath": "$item.notOnSale"
10349
+ "hiddenPath": "$item.saleTagHidden"
10350
+ }
10351
+ },
10352
+ {
10353
+ "id": "",
10354
+ "body": {
10355
+ "package": "himalaya",
10356
+ "type": "Text",
10357
+ "props": {
10358
+ "text": "$item.ribbon",
10359
+ "style": "caption",
10360
+ "color": "accentPrimary",
10361
+ "maxLines": 1
10362
+ }
10363
+ },
10364
+ "modifiers": {
10365
+ "background": {
10366
+ "token": "accentSurface"
10367
+ },
10368
+ "cornerRadius": 6,
10369
+ "padding": {
10370
+ "leading": 6,
10371
+ "trailing": 6,
10372
+ "top": 2,
10373
+ "bottom": 2
10374
+ },
10375
+ "hiddenPath": "$item.noRibbon"
10350
10376
  }
10351
10377
  },
10352
10378
  {
@@ -10789,7 +10815,33 @@ const SCREENS = runtimeSetting({
10789
10815
  "top": 2,
10790
10816
  "bottom": 2
10791
10817
  },
10792
- "hiddenPath": "$item.notOnSale"
10818
+ "hiddenPath": "$item.saleTagHidden"
10819
+ }
10820
+ },
10821
+ {
10822
+ "id": "",
10823
+ "body": {
10824
+ "package": "himalaya",
10825
+ "type": "Text",
10826
+ "props": {
10827
+ "text": "$item.ribbon",
10828
+ "style": "caption",
10829
+ "color": "accentPrimary",
10830
+ "maxLines": 1
10831
+ }
10832
+ },
10833
+ "modifiers": {
10834
+ "background": {
10835
+ "token": "accentSurface"
10836
+ },
10837
+ "cornerRadius": 6,
10838
+ "padding": {
10839
+ "leading": 6,
10840
+ "trailing": 6,
10841
+ "top": 2,
10842
+ "bottom": 2
10843
+ },
10844
+ "hiddenPath": "$item.noRibbon"
10793
10845
  }
10794
10846
  },
10795
10847
  {
@@ -11264,7 +11316,33 @@ const SCREENS = runtimeSetting({
11264
11316
  "top": 2,
11265
11317
  "bottom": 2
11266
11318
  },
11267
- "hiddenPath": "$item.notOnSale"
11319
+ "hiddenPath": "$item.saleTagHidden"
11320
+ }
11321
+ },
11322
+ {
11323
+ "id": "",
11324
+ "body": {
11325
+ "package": "himalaya",
11326
+ "type": "Text",
11327
+ "props": {
11328
+ "text": "$item.ribbon",
11329
+ "style": "caption",
11330
+ "color": "accentPrimary",
11331
+ "maxLines": 1
11332
+ }
11333
+ },
11334
+ "modifiers": {
11335
+ "background": {
11336
+ "token": "accentSurface"
11337
+ },
11338
+ "cornerRadius": 6,
11339
+ "padding": {
11340
+ "leading": 6,
11341
+ "trailing": 6,
11342
+ "top": 2,
11343
+ "bottom": 2
11344
+ },
11345
+ "hiddenPath": "$item.noRibbon"
11268
11346
  }
11269
11347
  },
11270
11348
  {
@@ -11715,7 +11793,33 @@ const SCREENS = runtimeSetting({
11715
11793
  "top": 2,
11716
11794
  "bottom": 2
11717
11795
  },
11718
- "hiddenPath": "$item.notOnSale"
11796
+ "hiddenPath": "$item.saleTagHidden"
11797
+ }
11798
+ },
11799
+ {
11800
+ "id": "",
11801
+ "body": {
11802
+ "package": "himalaya",
11803
+ "type": "Text",
11804
+ "props": {
11805
+ "text": "$item.ribbon",
11806
+ "style": "caption",
11807
+ "color": "accentPrimary",
11808
+ "maxLines": 1
11809
+ }
11810
+ },
11811
+ "modifiers": {
11812
+ "background": {
11813
+ "token": "accentSurface"
11814
+ },
11815
+ "cornerRadius": 6,
11816
+ "padding": {
11817
+ "leading": 6,
11818
+ "trailing": 6,
11819
+ "top": 2,
11820
+ "bottom": 2
11821
+ },
11822
+ "hiddenPath": "$item.noRibbon"
11719
11823
  }
11720
11824
  },
11721
11825
  {
@@ -14342,7 +14446,33 @@ const SCREENS = runtimeSetting({
14342
14446
  "top": 2,
14343
14447
  "bottom": 2
14344
14448
  },
14345
- "hiddenPath": "$item.notOnSale"
14449
+ "hiddenPath": "$item.saleTagHidden"
14450
+ }
14451
+ },
14452
+ {
14453
+ "id": "",
14454
+ "body": {
14455
+ "package": "himalaya",
14456
+ "type": "Text",
14457
+ "props": {
14458
+ "text": "$item.ribbon",
14459
+ "style": "caption",
14460
+ "color": "accentPrimary",
14461
+ "maxLines": 1
14462
+ }
14463
+ },
14464
+ "modifiers": {
14465
+ "background": {
14466
+ "token": "accentSurface"
14467
+ },
14468
+ "cornerRadius": 6,
14469
+ "padding": {
14470
+ "leading": 6,
14471
+ "trailing": 6,
14472
+ "top": 2,
14473
+ "bottom": 2
14474
+ },
14475
+ "hiddenPath": "$item.noRibbon"
14346
14476
  }
14347
14477
  },
14348
14478
  {
@@ -14798,7 +14928,33 @@ const SCREENS = runtimeSetting({
14798
14928
  "top": 2,
14799
14929
  "bottom": 2
14800
14930
  },
14801
- "hiddenPath": "$item.notOnSale"
14931
+ "hiddenPath": "$item.saleTagHidden"
14932
+ }
14933
+ },
14934
+ {
14935
+ "id": "",
14936
+ "body": {
14937
+ "package": "himalaya",
14938
+ "type": "Text",
14939
+ "props": {
14940
+ "text": "$item.ribbon",
14941
+ "style": "caption",
14942
+ "color": "accentPrimary",
14943
+ "maxLines": 1
14944
+ }
14945
+ },
14946
+ "modifiers": {
14947
+ "background": {
14948
+ "token": "accentSurface"
14949
+ },
14950
+ "cornerRadius": 6,
14951
+ "padding": {
14952
+ "leading": 6,
14953
+ "trailing": 6,
14954
+ "top": 2,
14955
+ "bottom": 2
14956
+ },
14957
+ "hiddenPath": "$item.noRibbon"
14802
14958
  }
14803
14959
  },
14804
14960
  {
@@ -15286,7 +15442,33 @@ const SCREENS = runtimeSetting({
15286
15442
  "top": 2,
15287
15443
  "bottom": 2
15288
15444
  },
15289
- "hiddenPath": "$item.notOnSale"
15445
+ "hiddenPath": "$item.saleTagHidden"
15446
+ }
15447
+ },
15448
+ {
15449
+ "id": "",
15450
+ "body": {
15451
+ "package": "himalaya",
15452
+ "type": "Text",
15453
+ "props": {
15454
+ "text": "$item.ribbon",
15455
+ "style": "caption",
15456
+ "color": "accentPrimary",
15457
+ "maxLines": 1
15458
+ }
15459
+ },
15460
+ "modifiers": {
15461
+ "background": {
15462
+ "token": "accentSurface"
15463
+ },
15464
+ "cornerRadius": 6,
15465
+ "padding": {
15466
+ "leading": 6,
15467
+ "trailing": 6,
15468
+ "top": 2,
15469
+ "bottom": 2
15470
+ },
15471
+ "hiddenPath": "$item.noRibbon"
15290
15472
  }
15291
15473
  },
15292
15474
  {
@@ -15750,7 +15932,33 @@ const SCREENS = runtimeSetting({
15750
15932
  "top": 2,
15751
15933
  "bottom": 2
15752
15934
  },
15753
- "hiddenPath": "$item.notOnSale"
15935
+ "hiddenPath": "$item.saleTagHidden"
15936
+ }
15937
+ },
15938
+ {
15939
+ "id": "",
15940
+ "body": {
15941
+ "package": "himalaya",
15942
+ "type": "Text",
15943
+ "props": {
15944
+ "text": "$item.ribbon",
15945
+ "style": "caption",
15946
+ "color": "accentPrimary",
15947
+ "maxLines": 1
15948
+ }
15949
+ },
15950
+ "modifiers": {
15951
+ "background": {
15952
+ "token": "accentSurface"
15953
+ },
15954
+ "cornerRadius": 6,
15955
+ "padding": {
15956
+ "leading": 6,
15957
+ "trailing": 6,
15958
+ "top": 2,
15959
+ "bottom": 2
15960
+ },
15961
+ "hiddenPath": "$item.noRibbon"
15754
15962
  }
15755
15963
  },
15756
15964
  {
@@ -68,6 +68,15 @@ export const listRooms = (identity: ChatIdentity): Promise<{ items: Raw[]; more:
68
68
  }
69
69
  return { items, more: true };
70
70
  });
71
+ /** How many of the member's BUSINESS chatrooms have unread messages, as the server counts them (capped at 100).
72
+ * Not the rooms themselves: the header badge needs only the total. A response without a valid count is
73
+ * unavailable, never zero. */
74
+ export const unreadRoomCount = (identity: ChatIdentity): Promise<number> => fenced(identity, async () => {
75
+ const page = await withToken(identity, (chatToken) => listChatroomsPage({ ...MEMBER, chatToken, pageSize: 1, onlyUnread: true, participantType: "business" }));
76
+ const count = page.unreadChatroomCount;
77
+ if (typeof count !== "number" || !Number.isSafeInteger(count) || count < 0) throw new Error("unavailable unread chat count");
78
+ return count;
79
+ });
71
80
  export const messagesPage = (identity: ChatIdentity, roomId: string): Promise<Raw[]> => fenced(identity, async () =>
72
81
  (await withToken(identity, (chatToken) => getMessagesPage(roomId, { ...MEMBER, chatToken, pageSize: 50, ordering: "Desc" }))).items as unknown as Raw[]);
73
82
 
@@ -58,8 +58,14 @@ export interface ProductCard {
58
58
  swatch1: string; swatch2: string; swatch3: string; swatch4: string; swatch5: string;
59
59
  swatch1Hidden: boolean; swatch2Hidden: boolean; swatch3Hidden: boolean; swatch4Hidden: boolean; swatch5Hidden: boolean;
60
60
  noSwatches: boolean;
61
- /** Hides the Sale tag / swatch row when it has nothing to show. */
61
+ /** Hides the tag row (Sale tag, ribbon, swatches) when it has nothing to show. */
62
62
  noTagRow: boolean;
63
+ /** The merchant's ribbon text ("New", "Best Seller"…), "" when the product has none. The ribbon replaces
64
+ * the price-derived Sale tag, so a product never carries two tags. */
65
+ ribbon: string;
66
+ noRibbon: boolean;
67
+ /** Hides the price-derived Sale tag: the product is not on sale, or its ribbon takes the tag's place. */
68
+ saleTagHidden: boolean;
63
69
  /** The Wix price before any App Store presentation rewrites `price`. */
64
70
  commercePrice: string;
65
71
  /** Original Wix sale metadata retained when App Store presentation hides it. */
@@ -179,6 +185,21 @@ function swatchFields(hexes: string[], onSale: boolean) {
179
185
  };
180
186
  }
181
187
 
188
+ /** The ribbon the merchant set, whichever catalog answered: V3 `{ id, name }`, V1 a plain string. Read through a
189
+ * local type, not a `StoreProduct` member: other workers already extend that type with their own `ribbon`. */
190
+ export function ribbonText(p: StoreProduct): string {
191
+ const ribbon = (p as { ribbon?: unknown }).ribbon;
192
+ const name = typeof ribbon === "string" ? ribbon : typeof (ribbon as { name?: unknown } | null | undefined)?.name === "string" ? (ribbon as { name: string }).name : "";
193
+ return name.trim();
194
+ }
195
+
196
+ /** What the tag row (Sale tag, ribbon, swatches) shows. One rule for every screen that rebuilds it, including
197
+ * after the App Store presentation changes `onSale`: the ribbon wins over the Sale tag, so a product never
198
+ * carries two, and the row hides when it has nothing to show. */
199
+ export function tagFields(onSale: boolean, noSwatches: boolean, ribbon: string | undefined) {
200
+ return { ribbon: ribbon ?? "", noRibbon: !ribbon, saleTagHidden: !onSale || !!ribbon, noTagRow: !onSale && noSwatches && !ribbon };
201
+ }
202
+
182
203
  export function productCard(p: StoreProduct, saved: Set<string> = savedIds()): ProductCard {
183
204
  const { now, was } = prices(p);
184
205
  const groups = productOptions(p);
@@ -187,11 +208,14 @@ export function productCard(p: StoreProduct, saved: Set<string> = savedIds()): P
187
208
  const image = productImage(p);
188
209
  const id = p.id ?? "";
189
210
  const onSale = !!was;
211
+ const ribbon = ribbonText(p);
212
+ const swatches = swatchFields((color?.choices ?? []).map((c) => c.colorCode ?? ""), onSale);
190
213
  return {
191
214
  id, name, image, hasImage: !!image, noImage: !image, initial: initials(name),
192
215
  price: now, wasPrice: was, onSale, notOnSale: !onSale,
193
216
  saved: saved.has(id), notSaved: !saved.has(id),
194
- ...swatchFields((color?.choices ?? []).map((c) => c.colorCode ?? ""), onSale),
217
+ ...swatches,
218
+ ...tagFields(onSale, swatches.noSwatches, ribbon),
195
219
  commercePrice: now,
196
220
  detailScreenId: "himi_product",
197
221
  };
@@ -7,7 +7,7 @@ import { searchStoreProducts, type StoreProduct } from "../_shared/himi-store.js
7
7
  import { createCollectionQuery } from "../_shared/collection-query.js";
8
8
  import { detailInputId, presence, presenceAfterError, type PresenceFlags } from "../_shared/detail-presence.js";
9
9
  import { stashCopy, copyParam, copyTemplate } from "../_shared/himi-copy.js";
10
- import { FACETS_BOOT, PAGE_SIZE, applyFacets, currencyOf, facetActions, idOf, readViewPrefs, toRows, toggleSaved, type FacetState } from "../_shared/himi-store-facets.js";
10
+ import { FACETS_BOOT, PAGE_SIZE, applyFacets, currencyOf, facetActions, idOf, readViewPrefs, tagFields, toRows, toggleSaved, type FacetState } from "../_shared/himi-store-facets.js";
11
11
  import { withIapPresentation } from "../_shared/iap-presentation.js";
12
12
 
13
13
  interface State extends FacetState, PresenceFlags {
@@ -187,8 +187,8 @@ const register = withIapPresentation<State>({
187
187
  const onSale = stored.commerceOnSale ?? row.onSale;
188
188
  return { ...row, price: price(row.id, row.commercePrice) || row.price,
189
189
  commerceWasPrice: wasPrice, commerceOnSale: onSale,
190
- ...(apple(row.id) ? { wasPrice: "", onSale: false, notOnSale: true, noTagRow: row.noSwatches }
191
- : { wasPrice, onSale, notOnSale: !onSale, noTagRow: !onSale && row.noSwatches }),
190
+ ...(apple(row.id) ? { wasPrice: "", onSale: false, notOnSale: true, ...tagFields(false, row.noSwatches, row.ribbon) }
191
+ : { wasPrice, onSale, notOnSale: !onSale, ...tagFields(onSale, row.noSwatches, row.ribbon) }),
192
192
  };
193
193
  }) }),
194
194
  });
@@ -17,7 +17,7 @@ import { withIapPresentation } from "../_shared/iap-presentation.js";
17
17
  import { stashCopy, copyParam, copyTemplate } from "../_shared/himi-copy.js";
18
18
  import { loadStoreCategories, type StoreCategoryCard } from "../_shared/himi-store-categories.js";
19
19
  import {
20
- FACETS_BOOT, PAGE_SIZE, applyFacets, countText, currencyOf, facetActions, idOf, option, readViewPrefs, selected, toRows, toggleSaved,
20
+ FACETS_BOOT, PAGE_SIZE, applyFacets, countText, currencyOf, facetActions, idOf, option, readViewPrefs, selected, tagFields, toRows, toggleSaved,
21
21
  type FacetState, type Option, type Row,
22
22
  } from "../_shared/himi-store-facets.js";
23
23
 
@@ -638,7 +638,7 @@ const register = withIapPresentation<S>({
638
638
  wasPrice: "",
639
639
  onSale: false,
640
640
  notOnSale: true,
641
- noTagRow: row.noSwatches,
641
+ ...tagFields(false, row.noSwatches, row.ribbon),
642
642
  };
643
643
  return {
644
644
  ...row,
@@ -646,7 +646,7 @@ const register = withIapPresentation<S>({
646
646
  wasPrice,
647
647
  onSale,
648
648
  notOnSale: !onSale,
649
- noTagRow: !onSale && row.noSwatches,
649
+ ...tagFields(onSale, row.noSwatches, row.ribbon),
650
650
  };
651
651
  }) };
652
652
  },