@wix/himalaya-cli 0.1032.0 → 0.1034.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.mjs +0 -2
- package/guides/getting-started.md +6 -2
- package/guides/wix-site-to-himi-app.md +9 -1
- package/package.json +2 -2
- package/templates/beauty-salon/dev/index.ts +398 -1
- package/templates/beauty-salon/tier5-src/_shared/collection-contract.ts +4 -1
- package/templates/beauty-salon/tier5-src/_shared/collection-service.ts +36 -5
- package/templates/beauty-salon/tier5-src/_shared/empty-flags.ts +33 -0
- package/templates/beauty-salon/tier5-src/himi-store-saved/index.ts +3 -2
- package/templates/beauty-salon/tier5-src/wix-spaces-collections/index.ts +3 -2
- package/templates/beauty-salon/tier5-src/wix-spaces-my-subscriptions/index.ts +11 -2
- package/templates/beauty-salon/tier5-src/wix-spaces-whats-new/index.ts +3 -2
- package/templates/beauty-salon-owner/dev/index.ts +1216 -0
- package/templates/beauty-salon-owner/tier5-src/_shared/collection-contract.ts +4 -1
- package/templates/beauty-salon-owner/tier5-src/_shared/collection-service.ts +36 -5
- package/templates/branded-lite/dev/index.ts +2239 -343
- package/templates/branded-lite/tier5-src/_shared/branded-load-state.ts +106 -0
- package/templates/branded-lite/tier5-src/_shared/collection-contract.ts +4 -1
- package/templates/branded-lite/tier5-src/_shared/collection-service.ts +36 -5
- package/templates/branded-lite/tier5-src/_shared/empty-flags.ts +33 -0
- package/templates/branded-lite/tier5-src/himi-branded-lite-badges/index.ts +20 -16
- package/templates/branded-lite/tier5-src/himi-branded-lite-coupons/index.ts +20 -20
- package/templates/branded-lite/tier5-src/himi-branded-lite-donations/index.ts +20 -16
- package/templates/branded-lite/tier5-src/himi-branded-lite-forms/index.ts +23 -31
- package/templates/branded-lite/tier5-src/himi-branded-lite-galleries/index.ts +19 -14
- package/templates/branded-lite/tier5-src/himi-branded-lite-giftcards/index.ts +20 -16
- package/templates/branded-lite/tier5-src/himi-branded-lite-inbox/index.ts +20 -15
- package/templates/branded-lite/tier5-src/himi-branded-lite-invoices/index.ts +20 -16
- package/templates/branded-lite/tier5-src/himi-branded-lite-loyalty/index.ts +20 -17
- package/templates/branded-lite/tier5-src/himi-branded-lite-notifications/index.ts +20 -18
- package/templates/branded-lite/tier5-src/himi-branded-lite-notifsettings/index.ts +23 -19
- package/templates/branded-lite/tier5-src/himi-branded-lite-podcasts/index.ts +1 -1
- package/templates/branded-lite/tier5-src/himi-branded-lite-reservations/index.ts +24 -20
- package/templates/branded-lite/tier5-src/himi-branded-lite-reviews/index.ts +20 -17
- package/templates/branded-lite/tier5-src/himi-branded-lite-videos/index.ts +19 -15
- package/templates/branded-lite/tier5-src/himi-store-saved/index.ts +3 -2
- package/templates/branded-lite/tier5-src/wix-spaces-collections/index.ts +3 -2
- package/templates/branded-lite/tier5-src/wix-spaces-forum/index.ts +3 -2
- package/templates/branded-lite/tier5-src/wix-spaces-members/index.ts +19 -6
- package/templates/branded-lite/tier5-src/wix-spaces-my-subscriptions/index.ts +11 -2
- package/templates/branded-lite/tier5-src/wix-spaces-new-message/index.ts +3 -2
- package/templates/branded-lite/tier5-src/wix-spaces-whats-new/index.ts +3 -2
- package/templates/community-club/dev/index.ts +283 -2
- package/templates/community-club/tier5-src/_shared/collection-contract.ts +4 -1
- package/templates/community-club/tier5-src/_shared/collection-service.ts +36 -5
- package/templates/community-club/tier5-src/_shared/empty-flags.ts +33 -0
- package/templates/community-club/tier5-src/wix-spaces-whats-new/index.ts +3 -2
- package/templates/community-club-owner/dev/index.ts +1216 -0
- package/templates/community-club-owner/tier5-src/_shared/collection-contract.ts +4 -1
- package/templates/community-club-owner/tier5-src/_shared/collection-service.ts +36 -5
- package/templates/events-meetups/dev/index.ts +197 -1
- package/templates/events-meetups/tier5-src/_shared/collection-contract.ts +4 -1
- package/templates/events-meetups/tier5-src/_shared/collection-service.ts +36 -5
- package/templates/events-meetups/tier5-src/_shared/empty-flags.ts +33 -0
- package/templates/events-meetups/tier5-src/wix-spaces-whats-new/index.ts +3 -2
- package/templates/events-meetups-owner/dev/index.ts +1088 -0
- package/templates/events-meetups-owner/tier5-src/_shared/collection-contract.ts +4 -1
- package/templates/events-meetups-owner/tier5-src/_shared/collection-service.ts +36 -5
- package/templates/gym-fitness/dev/index.ts +462 -1
- package/templates/gym-fitness/tier5-src/_shared/collection-contract.ts +4 -1
- package/templates/gym-fitness/tier5-src/_shared/collection-service.ts +36 -5
- package/templates/gym-fitness/tier5-src/_shared/empty-flags.ts +33 -0
- package/templates/gym-fitness/tier5-src/himi-store-saved/index.ts +3 -2
- package/templates/gym-fitness/tier5-src/wix-spaces-collections/index.ts +3 -2
- package/templates/gym-fitness/tier5-src/wix-spaces-my-subscriptions/index.ts +11 -2
- package/templates/gym-fitness/tier5-src/wix-spaces-whats-new/index.ts +3 -2
- package/templates/gym-fitness-owner/dev/index.ts +1280 -0
- package/templates/gym-fitness-owner/tier5-src/_shared/collection-contract.ts +4 -1
- package/templates/gym-fitness-owner/tier5-src/_shared/collection-service.ts +36 -5
- package/templates/nonprofit-cause/dev/index.ts +264 -1
- package/templates/nonprofit-cause/tier5-src/_shared/collection-contract.ts +4 -1
- package/templates/nonprofit-cause/tier5-src/_shared/collection-service.ts +36 -5
- package/templates/nonprofit-cause/tier5-src/_shared/empty-flags.ts +33 -0
- package/templates/nonprofit-cause/tier5-src/wix-spaces-my-subscriptions/index.ts +11 -2
- package/templates/nonprofit-cause/tier5-src/wix-spaces-whats-new/index.ts +3 -2
- package/templates/nonprofit-cause-owner/dev/index.ts +1152 -0
- package/templates/nonprofit-cause-owner/tier5-src/_shared/collection-contract.ts +4 -1
- package/templates/nonprofit-cause-owner/tier5-src/_shared/collection-service.ts +36 -5
- package/templates/owner-lite/dev/index.ts +1280 -0
- package/templates/owner-lite/tier5-src/_shared/collection-contract.ts +4 -1
- package/templates/owner-lite/tier5-src/_shared/collection-service.ts +36 -5
- package/templates/podcast-creator/dev/index.ts +286 -23
- package/templates/podcast-creator/tier5-src/_shared/collection-contract.ts +4 -1
- package/templates/podcast-creator/tier5-src/_shared/collection-service.ts +36 -5
- package/templates/podcast-creator/tier5-src/_shared/empty-flags.ts +33 -0
- package/templates/podcast-creator/tier5-src/himi-branded-lite-podcasts/index.ts +1 -1
- package/templates/podcast-creator/tier5-src/wix-spaces-my-subscriptions/index.ts +11 -2
- package/templates/podcast-creator/tier5-src/wix-spaces-whats-new/index.ts +3 -2
- package/templates/podcast-creator-owner/dev/index.ts +1216 -0
- package/templates/podcast-creator-owner/tier5-src/_shared/collection-contract.ts +4 -1
- package/templates/podcast-creator-owner/tier5-src/_shared/collection-service.ts +36 -5
- package/templates/portfolio-creative/dev/index.ts +353 -23
- package/templates/portfolio-creative/tier5-src/_shared/collection-contract.ts +4 -1
- package/templates/portfolio-creative/tier5-src/_shared/collection-service.ts +36 -5
- package/templates/portfolio-creative/tier5-src/_shared/empty-flags.ts +33 -0
- package/templates/portfolio-creative/tier5-src/himi-store-saved/index.ts +3 -2
- package/templates/portfolio-creative/tier5-src/wix-spaces-collections/index.ts +3 -2
- package/templates/portfolio-creative/tier5-src/wix-spaces-whats-new/index.ts +3 -2
- package/templates/portfolio-creative-owner/dev/index.ts +1216 -0
- package/templates/portfolio-creative-owner/tier5-src/_shared/collection-contract.ts +4 -1
- package/templates/portfolio-creative-owner/tier5-src/_shared/collection-service.ts +36 -5
- package/templates/restaurant/dev/index.ts +197 -1
- package/templates/restaurant/tier5-src/_shared/collection-contract.ts +4 -1
- package/templates/restaurant/tier5-src/_shared/collection-service.ts +36 -5
- package/templates/restaurant/tier5-src/_shared/empty-flags.ts +33 -0
- package/templates/restaurant/tier5-src/wix-spaces-whats-new/index.ts +3 -2
- package/templates/restaurant-owner/dev/index.ts +1280 -0
- package/templates/restaurant-owner/tier5-src/_shared/collection-contract.ts +4 -1
- package/templates/restaurant-owner/tier5-src/_shared/collection-service.ts +36 -5
- package/templates/retail-store/dev/index.ts +203 -1
- package/templates/retail-store/tier5-src/_shared/collection-contract.ts +4 -1
- package/templates/retail-store/tier5-src/_shared/collection-service.ts +36 -5
- package/templates/retail-store/tier5-src/_shared/empty-flags.ts +33 -0
- package/templates/retail-store/tier5-src/himi-store-saved/index.ts +3 -2
- package/templates/retail-store/tier5-src/wix-spaces-collections/index.ts +3 -2
- package/templates/retail-store/tier5-src/wix-spaces-whats-new/index.ts +3 -2
- package/templates/retail-store-owner/dev/index.ts +1152 -0
- package/templates/retail-store-owner/tier5-src/_shared/collection-contract.ts +4 -1
- package/templates/retail-store-owner/tier5-src/_shared/collection-service.ts +36 -5
- package/templates/yoga-studio/dev/index.ts +392 -1
- package/templates/yoga-studio/tier5-src/_shared/collection-contract.ts +4 -1
- package/templates/yoga-studio/tier5-src/_shared/collection-service.ts +36 -5
- package/templates/yoga-studio/tier5-src/_shared/empty-flags.ts +33 -0
- package/templates/yoga-studio/tier5-src/wix-spaces-my-subscriptions/index.ts +11 -2
- package/templates/yoga-studio/tier5-src/wix-spaces-whats-new/index.ts +3 -2
- package/templates/yoga-studio-owner/dev/index.ts +1152 -0
- package/templates/yoga-studio-owner/tier5-src/_shared/collection-contract.ts +4 -1
- package/templates/yoga-studio-owner/tier5-src/_shared/collection-service.ts +36 -5
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
// himi-branded-lite-giftcards —
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
// labelled "Sample content" banner. Real gift cards always win the moment any exist.
|
|
1
|
+
// himi-branded-lite-giftcards — reads the visitor's real Wix Gift Cards (queryGiftCards).
|
|
2
|
+
// a failed query is an error with Retry (or Sign in when Wix refuses the
|
|
3
|
+
// visitor) and an empty one is a real empty state — never sample rows presented as
|
|
4
|
+
// the customer's own. Samples appear only in the host's explicit sample preview
|
|
5
|
+
// (_shared/branded-load-state.ts).
|
|
7
6
|
import { defineService } from "../_shared/collection-service.js";
|
|
7
|
+
import { LOADING, loaded, loadFailed, type LoadCopy, type LoadFlags } from "../_shared/branded-load-state.js";
|
|
8
8
|
import { queryGiftCards, type WixGiftCard } from "@himalaya/wix-gift-cards";
|
|
9
9
|
|
|
10
10
|
interface Row { id: string; title: string; subtitle: string }
|
|
11
|
-
interface S {
|
|
12
|
-
status: "loading" | "ready";
|
|
11
|
+
interface S extends LoadFlags {
|
|
13
12
|
cards: Row[]; emptyText: string;
|
|
14
13
|
isMock: boolean; notMock: boolean; /** #2849 — hiddenWhen() hides on TRUE, so these are inverted: the empty-state banner
|
|
15
14
|
* shows only when the site really has none, and the unavailable one only when the
|
|
@@ -44,21 +43,26 @@ const MOCK: Row[] = [
|
|
|
44
43
|
{ id: "sample-3", title: "Gift card ····3312", subtitle: "Balance $0.00" },
|
|
45
44
|
];
|
|
46
45
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
/** sample rows reach the screen ONLY in the host's explicit sample preview;
|
|
47
|
+
* a failed or empty query is an honest error / empty state (branded-load-state.ts). */
|
|
48
|
+
const COPY: LoadCopy<Row> = {
|
|
49
|
+
prefix: "giftCards",
|
|
50
|
+
empty: "You don't have any gift cards yet.",
|
|
51
|
+
error: "Your gift cards couldn't be loaded.",
|
|
52
|
+
signIn: "Sign in to see your gift cards.",
|
|
53
|
+
sample: () => MOCK.map((r) => ({ ...r })),
|
|
54
|
+
};
|
|
50
55
|
|
|
51
56
|
const svc = defineService<S, { load: (s: S) => Promise<S> }>("himiBrandedGiftCards", {
|
|
52
|
-
state: {
|
|
57
|
+
state: { ...LOADING, cards: [], emptyText: "" },
|
|
53
58
|
actions: {
|
|
54
59
|
load: async (s) => {
|
|
55
60
|
try {
|
|
56
61
|
const r = await queryGiftCards({ query: { cursorPaging: { limit: 20 } } });
|
|
57
62
|
const cards = (r.giftCards ?? []).map(norm);
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
return mockState(s, "unavailable");
|
|
63
|
+
return { ...s, ...loaded("cards", cards, COPY) };
|
|
64
|
+
} catch (err) {
|
|
65
|
+
return { ...s, ...loadFailed("cards", err, COPY) };
|
|
62
66
|
}
|
|
63
67
|
},
|
|
64
68
|
},
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
// himi-branded-lite-inbox —
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
1
|
+
// himi-branded-lite-inbox — reads the visitor's real Wix Inbox conversations (listConversations).
|
|
2
|
+
// a failed query is an error with Retry (or Sign in when Wix refuses the
|
|
3
|
+
// visitor) and an empty one is a real empty state — never sample rows presented as
|
|
4
|
+
// the customer's own. Samples appear only in the host's explicit sample preview
|
|
5
|
+
// (_shared/branded-load-state.ts).
|
|
6
6
|
//
|
|
7
7
|
// Inbox exposes no list-messages endpoint (only listConversations + single getMessage),
|
|
8
8
|
// so this is a conversation LIST — same read-view scope as the Galleries/Forms verticals.
|
|
9
9
|
import { defineService } from "../_shared/collection-service.js";
|
|
10
|
+
import { LOADING, loaded, loadFailed, type LoadCopy, type LoadFlags } from "../_shared/branded-load-state.js";
|
|
10
11
|
import { listConversations, type WixConversation } from "@himalaya/wix-inbox";
|
|
11
12
|
|
|
12
13
|
interface Row { id: string; title: string; subtitle: string }
|
|
13
|
-
interface S {
|
|
14
|
-
status: "loading" | "ready";
|
|
14
|
+
interface S extends LoadFlags {
|
|
15
15
|
conversations: Row[]; emptyText: string;
|
|
16
16
|
isMock: boolean; notMock: boolean; /** #2849 — hiddenWhen() hides on TRUE, so these are inverted: the empty-state banner
|
|
17
17
|
* shows only when the site really has none, and the unavailable one only when the
|
|
@@ -43,21 +43,26 @@ const MOCK: Row[] = [
|
|
|
43
43
|
{ id: "sample-team", title: "The Team", subtitle: "Welcome 👋 Thanks for joining us!" },
|
|
44
44
|
];
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
/** sample rows reach the screen ONLY in the host's explicit sample preview;
|
|
47
|
+
* a failed or empty query is an honest error / empty state (branded-load-state.ts). */
|
|
48
|
+
const COPY: LoadCopy<Row> = {
|
|
49
|
+
prefix: "inbox",
|
|
50
|
+
empty: "No messages yet.",
|
|
51
|
+
error: "Your messages couldn't be loaded.",
|
|
52
|
+
signIn: "Sign in to see your messages.",
|
|
53
|
+
sample: () => MOCK.map((r) => ({ ...r })),
|
|
54
|
+
};
|
|
49
55
|
|
|
50
56
|
const svc = defineService<S, { load: (s: S) => Promise<S> }>("himiBrandedInbox", {
|
|
51
|
-
state: {
|
|
57
|
+
state: { ...LOADING, conversations: [], emptyText: "" },
|
|
52
58
|
actions: {
|
|
53
59
|
load: async (s) => {
|
|
54
60
|
try {
|
|
55
61
|
const r = await listConversations({ paging: { limit: 50 } });
|
|
56
62
|
const conversations = (r.conversations ?? []).map(norm);
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
return mockState(s, "unavailable");
|
|
63
|
+
return { ...s, ...loaded("conversations", conversations, COPY) };
|
|
64
|
+
} catch (err) {
|
|
65
|
+
return { ...s, ...loadFailed("conversations", err, COPY) };
|
|
61
66
|
}
|
|
62
67
|
},
|
|
63
68
|
},
|
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
// himi-branded-lite-invoices —
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
// labelled "Sample content" banner. Real invoices always win the moment any exist.
|
|
1
|
+
// himi-branded-lite-invoices — reads the member's real Wix Invoices (queryInvoices).
|
|
2
|
+
// a failed query is an error with Retry (or Sign in when Wix refuses the
|
|
3
|
+
// visitor) and an empty one is a real empty state — never sample rows presented as
|
|
4
|
+
// the customer's own. Samples appear only in the host's explicit sample preview
|
|
5
|
+
// (_shared/branded-load-state.ts).
|
|
7
6
|
import { defineService } from "../_shared/collection-service.js";
|
|
7
|
+
import { LOADING, loaded, loadFailed, type LoadCopy, type LoadFlags } from "../_shared/branded-load-state.js";
|
|
8
8
|
import { queryInvoices, type WixInvoice } from "@himalaya/wix-invoices";
|
|
9
9
|
|
|
10
10
|
interface Row { id: string; title: string; subtitle: string }
|
|
11
|
-
interface S {
|
|
12
|
-
status: "loading" | "ready";
|
|
11
|
+
interface S extends LoadFlags {
|
|
13
12
|
invoices: Row[]; emptyText: string;
|
|
14
13
|
isMock: boolean; notMock: boolean; /** #2849 — hiddenWhen() hides on TRUE, so these are inverted: the empty-state banner
|
|
15
14
|
* shows only when the site really has none, and the unavailable one only when the
|
|
@@ -45,21 +44,26 @@ const MOCK: Row[] = [
|
|
|
45
44
|
{ id: "sample-1042", title: "Invoice #1042", subtitle: "Overdue · $45.00" },
|
|
46
45
|
];
|
|
47
46
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
/** sample rows reach the screen ONLY in the host's explicit sample preview;
|
|
48
|
+
* a failed or empty query is an honest error / empty state (branded-load-state.ts). */
|
|
49
|
+
const COPY: LoadCopy<Row> = {
|
|
50
|
+
prefix: "invoices",
|
|
51
|
+
empty: "You don't have any invoices yet.",
|
|
52
|
+
error: "Your invoices couldn't be loaded.",
|
|
53
|
+
signIn: "Sign in to see your invoices.",
|
|
54
|
+
sample: () => MOCK.map((r) => ({ ...r })),
|
|
55
|
+
};
|
|
51
56
|
|
|
52
57
|
const svc = defineService<S, { load: (s: S) => Promise<S> }>("himiBrandedInvoices", {
|
|
53
|
-
state: {
|
|
58
|
+
state: { ...LOADING, invoices: [], emptyText: "" },
|
|
54
59
|
actions: {
|
|
55
60
|
load: async (s) => {
|
|
56
61
|
try {
|
|
57
62
|
const r = await queryInvoices({ query: { paging: { limit: 20 } } });
|
|
58
63
|
const invoices = (r.invoices ?? []).filter((v) => v.archived !== true).map(norm);
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
return mockState(s, "unavailable");
|
|
64
|
+
return { ...s, ...loaded("invoices", invoices, COPY) };
|
|
65
|
+
} catch (err) {
|
|
66
|
+
return { ...s, ...loadFailed("invoices", err, COPY) };
|
|
63
67
|
}
|
|
64
68
|
},
|
|
65
69
|
},
|
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
// himi-branded-lite-loyalty —
|
|
2
|
-
//
|
|
3
|
-
// real
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
// flags `isMock`, so the screen shows a clearly-labelled "Sample content" banner.
|
|
7
|
-
// Real rewards always win the moment the program is active with rewards.
|
|
1
|
+
// himi-branded-lite-loyalty — reads the real Wix Loyalty program + rewards (getLoyaltyProgram + listLoyaltyRewards).
|
|
2
|
+
// a failed query is an error with Retry (or Sign in when Wix refuses the
|
|
3
|
+
// visitor) and an empty one is a real empty state — never sample rows presented as
|
|
4
|
+
// the customer's own. Samples appear only in the host's explicit sample preview
|
|
5
|
+
// (_shared/branded-load-state.ts).
|
|
8
6
|
import { defineService } from "../_shared/collection-service.js";
|
|
7
|
+
import { LOADING, loaded, loadFailed, type LoadCopy, type LoadFlags } from "../_shared/branded-load-state.js";
|
|
9
8
|
import { getLoyaltyProgram, listLoyaltyRewards, type WixLoyaltyReward } from "@himalaya/wix-loyalty";
|
|
10
9
|
|
|
11
10
|
interface Row { id: string; name: string; subtitle: string }
|
|
12
|
-
interface S {
|
|
13
|
-
status: "loading" | "ready";
|
|
11
|
+
interface S extends LoadFlags {
|
|
14
12
|
programName: string; unit: string;
|
|
15
13
|
rewards: Row[]; emptyText: string;
|
|
16
14
|
isMock: boolean; notMock: boolean; /** #2849 — hiddenWhen() hides on TRUE, so these are inverted: the empty-state banner
|
|
@@ -39,12 +37,18 @@ const MOCK: Row[] = [
|
|
|
39
37
|
{ id: "sample-gift", name: "Free welcome gift", subtitle: "1,000 points" },
|
|
40
38
|
];
|
|
41
39
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
/** sample rows reach the screen ONLY in the host's explicit sample preview;
|
|
41
|
+
* a failed or empty query is an honest error / empty state (branded-load-state.ts). */
|
|
42
|
+
const COPY: LoadCopy<Row> = {
|
|
43
|
+
prefix: "loyalty",
|
|
44
|
+
empty: "No rewards to redeem yet.",
|
|
45
|
+
error: "The rewards program couldn't be loaded.",
|
|
46
|
+
signIn: "Sign in to see your points and rewards.",
|
|
47
|
+
sample: () => MOCK.map((r) => ({ ...r })),
|
|
48
|
+
};
|
|
45
49
|
|
|
46
50
|
const svc = defineService<S, { load: (s: S) => Promise<S> }>("himiBrandedLoyalty", {
|
|
47
|
-
state: {
|
|
51
|
+
state: { ...LOADING, programName: "Rewards", unit: "points", rewards: [], emptyText: "" },
|
|
48
52
|
actions: {
|
|
49
53
|
load: async (s) => {
|
|
50
54
|
try {
|
|
@@ -54,10 +58,9 @@ const svc = defineService<S, { load: (s: S) => Promise<S> }>("himiBrandedLoyalty
|
|
|
54
58
|
const programName = (p?.name || "Rewards").trim() || "Rewards";
|
|
55
59
|
const r = await listLoyaltyRewards();
|
|
56
60
|
const rewards = (r.rewards ?? []).filter((x) => x.active !== false).map((x) => norm(x, unit));
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
return mockState(s, "unavailable");
|
|
61
|
+
return { ...s, programName, unit, ...loaded("rewards", rewards, COPY) };
|
|
62
|
+
} catch (err) {
|
|
63
|
+
return { ...s, ...loadFailed("rewards", err, COPY) };
|
|
61
64
|
}
|
|
62
65
|
},
|
|
63
66
|
},
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
// himi-branded-lite-notifications —
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
// SAMPLE notifications and flags `isMock`, so the screen shows a clearly-labelled
|
|
7
|
-
// "Sample content" banner. Real notifications always win the moment any exist.
|
|
1
|
+
// himi-branded-lite-notifications — reads the member's notifications via Members Feed Viewer (queryNotifications).
|
|
2
|
+
// a failed query is an error with Retry (or Sign in when Wix refuses the
|
|
3
|
+
// visitor) and an empty one is a real empty state — never sample rows presented as
|
|
4
|
+
// the customer's own. Samples appear only in the host's explicit sample preview
|
|
5
|
+
// (_shared/branded-load-state.ts).
|
|
8
6
|
// mark-one-read / mark-all-read stay wired: they update state optimistically and
|
|
9
7
|
// best-effort the real write (a no-op on sample rows).
|
|
10
8
|
import { defineService } from "../_shared/collection-service.js";
|
|
9
|
+
import { LOADING, loaded, loadFailed, type LoadCopy, type LoadFlags } from "../_shared/branded-load-state.js";
|
|
11
10
|
import { queryNotifications, markRead, markAllRead, type MfvNotification } from "@himalaya/wix-members-feed-viewer";
|
|
12
11
|
|
|
13
12
|
interface Row {
|
|
@@ -22,8 +21,7 @@ interface Row {
|
|
|
22
21
|
initial: string;
|
|
23
22
|
dest: string;
|
|
24
23
|
}
|
|
25
|
-
interface S {
|
|
26
|
-
status: "loading" | "ready";
|
|
24
|
+
interface S extends LoadFlags {
|
|
27
25
|
items: Row[]; emptyText: string;
|
|
28
26
|
isMock: boolean; notMock: boolean;
|
|
29
27
|
/** #2849 — hiddenWhen() hides on TRUE, so these are inverted: the empty-state banner
|
|
@@ -92,25 +90,29 @@ const MOCK: Row[] = [
|
|
|
92
90
|
{ id: "sample-offer", name: "New offer just for you", subtitle: "15% off your next order · 3d ago", unread: false, unreadDot: "", photo: "", initial: "%", dest: "" },
|
|
93
91
|
];
|
|
94
92
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
93
|
+
/** sample rows reach the screen ONLY in the host's explicit sample preview;
|
|
94
|
+
* a failed or empty query is an honest error / empty state (branded-load-state.ts). */
|
|
95
|
+
const COPY: LoadCopy<Row> = {
|
|
96
|
+
prefix: "notifications",
|
|
97
|
+
empty: "You're all caught up — no notifications yet.",
|
|
98
|
+
error: "Notifications couldn't be loaded.",
|
|
99
|
+
signIn: "Sign in to see your notifications.",
|
|
100
|
+
sample: () => MOCK.map((r) => ({ ...r })),
|
|
101
|
+
};
|
|
99
102
|
|
|
100
103
|
const svc = defineService<S, {
|
|
101
104
|
load: (s: S) => Promise<S>;
|
|
102
105
|
markOneRead: (s: S, id: string) => Promise<S>;
|
|
103
106
|
markAll: (s: S) => Promise<S>;
|
|
104
107
|
}>("himiBrandedNotifications", {
|
|
105
|
-
state: {
|
|
108
|
+
state: { ...LOADING, items: [], emptyText: "" },
|
|
106
109
|
actions: {
|
|
107
110
|
load: async (s) => {
|
|
108
111
|
try {
|
|
109
112
|
const items = (await queryNotifications(25)).map(norm);
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
return mockState(s, "unavailable");
|
|
113
|
+
return { ...s, ...loaded("items", items, COPY) };
|
|
114
|
+
} catch (err) {
|
|
115
|
+
return { ...s, ...loadFailed("items", err, COPY) };
|
|
114
116
|
}
|
|
115
117
|
},
|
|
116
118
|
// Mark one read; optimistically clear its dot. Real write is best-effort and
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
// himi-branded-lite-notifsettings —
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
// substitutes representative SAMPLE topics and flags `isMock`, so the screen shows
|
|
7
|
-
// a clearly-labelled "Sample content" banner. Real topics always win the moment
|
|
1
|
+
// himi-branded-lite-notifsettings — reads the site's notification topics + the member's preferences.
|
|
2
|
+
// a failed query is an error with Retry (or Sign in when Wix refuses the
|
|
3
|
+
// visitor) and an empty one is a real empty state — never sample rows presented as
|
|
4
|
+
// the customer's own. Samples appear only in the host's explicit sample preview
|
|
5
|
+
// (_shared/branded-load-state.ts).
|
|
8
6
|
// any exist. INTERACTIVE: tapping a row toggles that topic On/Off — optimistic +
|
|
9
7
|
// best-effort upsertMyNotificationPreferences (a no-op on sample rows).
|
|
10
8
|
import { defineService } from "@himalaya/state";
|
|
9
|
+
import { withEmptyFlags } from "../_shared/empty-flags.js";
|
|
10
|
+
import { LOADING, loaded, loadFailed, type LoadCopy, type LoadFlags } from "../_shared/branded-load-state.js";
|
|
11
11
|
import {
|
|
12
12
|
getNotificationTopics,
|
|
13
13
|
getMyNotificationPreferences,
|
|
@@ -30,8 +30,7 @@ const CHANNEL = "MOBILE";
|
|
|
30
30
|
interface Row { id: string; name: string; subtitle: string; note: string; on: boolean; locked: boolean;
|
|
31
31
|
/** Inverse of `locked` (hiddenWhen hides on TRUE) and the plain On/Off a locked row shows. */
|
|
32
32
|
notLocked: boolean; stateLabel: string }
|
|
33
|
-
interface S {
|
|
34
|
-
status: "loading" | "ready";
|
|
33
|
+
interface S extends LoadFlags {
|
|
35
34
|
topics: Row[]; emptyText: string;
|
|
36
35
|
isMock: boolean; notMock: boolean; /** #2849 — hiddenWhen() hides on TRUE, so these are inverted: the empty-state banner
|
|
37
36
|
* shows only when the site really has none, and the unavailable one only when the
|
|
@@ -82,15 +81,21 @@ const MOCK: Row[] = [
|
|
|
82
81
|
row("sample-community", "Community activity", true),
|
|
83
82
|
];
|
|
84
83
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
84
|
+
/** sample rows reach the screen ONLY in the host's explicit sample preview;
|
|
85
|
+
* a failed or empty query is an honest error / empty state (branded-load-state.ts). */
|
|
86
|
+
const COPY: LoadCopy<Row> = {
|
|
87
|
+
prefix: "notifsettings",
|
|
88
|
+
empty: "No notification topics to manage yet.",
|
|
89
|
+
error: "Notification settings couldn't be loaded.",
|
|
90
|
+
signIn: "Sign in to manage your notifications.",
|
|
91
|
+
sample: () => MOCK.map((r) => ({ ...r })),
|
|
92
|
+
};
|
|
88
93
|
|
|
89
94
|
const svc = defineService<S, {
|
|
90
95
|
load: (s: S) => Promise<S>;
|
|
91
96
|
toggle: (s: S, p?: { id?: string; value?: unknown }) => Promise<S>;
|
|
92
|
-
}>("himiBrandedNotifSettings", {
|
|
93
|
-
state: {
|
|
97
|
+
}>("himiBrandedNotifSettings", withEmptyFlags({
|
|
98
|
+
state: { ...LOADING, topics: [], emptyText: "" },
|
|
94
99
|
actions: {
|
|
95
100
|
load: async (s) => {
|
|
96
101
|
try {
|
|
@@ -100,10 +105,9 @@ const svc = defineService<S, {
|
|
|
100
105
|
]);
|
|
101
106
|
const prefs = readPreferences(prefsRes);
|
|
102
107
|
const topics = readTopics(topicsRes).map((t) => norm(t, prefs));
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
return mockState(s, "unavailable");
|
|
108
|
+
return { ...s, ...loaded("topics", topics, COPY) };
|
|
109
|
+
} catch (err) {
|
|
110
|
+
return { ...s, ...loadFailed("topics", err, COPY) };
|
|
107
111
|
}
|
|
108
112
|
},
|
|
109
113
|
// Flip one topic's On/Off. Optimistic (updates the row immediately); the real
|
|
@@ -132,6 +136,6 @@ const svc = defineService<S, {
|
|
|
132
136
|
return { ...s, topics };
|
|
133
137
|
},
|
|
134
138
|
},
|
|
135
|
-
});
|
|
139
|
+
}, { topics: "noTopics" }));
|
|
136
140
|
svc.load();
|
|
137
141
|
export { svc };
|
|
@@ -154,7 +154,7 @@ const svc = defineService<S, {
|
|
|
154
154
|
load: async (s, arg) => {
|
|
155
155
|
const configured = typeof (arg as { feedUrl?: unknown } | undefined)?.feedUrl === "string" ? String((arg as { feedUrl: string }).feedUrl).trim() : "";
|
|
156
156
|
if (!configured) {
|
|
157
|
-
return derive({ ...s, status: "ready", episodes: [], emptyText: "
|
|
157
|
+
return derive({ ...s, status: "ready", episodes: [], emptyText: "No episodes yet — check back soon.", isMock: false, notMock: true, mockBanner: "" });
|
|
158
158
|
}
|
|
159
159
|
try {
|
|
160
160
|
const api = host().wixApi;
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
// himi-branded-lite-reservations — branded-lite "My Reservations" worker
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
// reservation cancels it — optimistic + best-effort cancelReservation (no-op on
|
|
9
|
-
// sample rows).
|
|
1
|
+
// himi-branded-lite-reservations — branded-lite "My Reservations" worker. Reads
|
|
2
|
+
// the member's real Wix Table Reservations (queryReservations). A failed query is an
|
|
3
|
+
// error with Retry (or Sign in when Wix refuses the visitor), an empty one is a real
|
|
4
|
+
// empty state — never invented bookings labelled "tap to cancel". Sample rows
|
|
5
|
+
// appear only in the host's explicit sample preview (branded-load-state.ts).
|
|
6
|
+
// INTERACTIVE: tapping an upcoming reservation cancels it — optimistic + best-effort
|
|
7
|
+
// cancelReservation (no-op on sample rows).
|
|
10
8
|
//
|
|
11
9
|
// RFC 0052 consumer: the list is a `himalaya.Agenda` — chronological, grouped
|
|
12
10
|
// by LOCAL day under sticky headers. A reservation list is a diary, and the
|
|
@@ -14,12 +12,12 @@
|
|
|
14
12
|
// no row knew what day the row above it was on. `Agenda` owns the day headers
|
|
15
13
|
// and the time column, so a row carries only what is actually per-reservation.
|
|
16
14
|
import { defineService } from "@himalaya/state";
|
|
15
|
+
import { LOADING, loaded, loadFailed, type LoadCopy, type LoadFlags } from "../_shared/branded-load-state.js";
|
|
17
16
|
import { queryReservations, cancelReservation, type WixReservation } from "@himalaya/wix-table-reservations";
|
|
18
17
|
import { type CalendarEvent } from "@himalaya/time";
|
|
19
18
|
|
|
20
19
|
interface Row { id: string; revision: string; title: string; subtitle: string; cancellable: boolean; canceled: boolean; start: string; raw: string }
|
|
21
|
-
interface S {
|
|
22
|
-
status: "loading" | "ready";
|
|
20
|
+
interface S extends LoadFlags {
|
|
23
21
|
reservations: Row[];
|
|
24
22
|
/** The Agenda wire shape, derived from `reservations` on every transition. */
|
|
25
23
|
events: CalendarEvent[];
|
|
@@ -122,8 +120,17 @@ function mockRows(): Row[] {
|
|
|
122
120
|
];
|
|
123
121
|
}
|
|
124
122
|
|
|
125
|
-
|
|
126
|
-
|
|
123
|
+
const COPY: LoadCopy<Row> = {
|
|
124
|
+
prefix: "reservations",
|
|
125
|
+
empty: "You don't have any reservations yet.",
|
|
126
|
+
error: "Your reservations couldn't be loaded.",
|
|
127
|
+
signIn: "Sign in to see your reservations.",
|
|
128
|
+
sample: mockRows,
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
/** Every settled load goes through withEvents so the Agenda never drifts from the rows. */
|
|
132
|
+
function settle(s: S, next: Pick<S, "reservations" | "emptyText"> & LoadFlags): S {
|
|
133
|
+
return withEvents({ ...s, ...next }, next.reservations);
|
|
127
134
|
}
|
|
128
135
|
|
|
129
136
|
/** The reservation id out of a tap. `Agenda.onSelectEvent` dispatches
|
|
@@ -141,7 +148,7 @@ const svc = defineService<S, {
|
|
|
141
148
|
load: (s: S) => Promise<S>;
|
|
142
149
|
cancel: (s: S, p?: unknown) => Promise<S>;
|
|
143
150
|
}>("himiBrandedReservations", {
|
|
144
|
-
state: {
|
|
151
|
+
state: { ...LOADING, reservations: [], events: [], emptyText: "" },
|
|
145
152
|
actions: {
|
|
146
153
|
load: async (s) => {
|
|
147
154
|
try {
|
|
@@ -149,12 +156,9 @@ const svc = defineService<S, {
|
|
|
149
156
|
// to hand it chronological order rather than newest-first.
|
|
150
157
|
const r = await queryReservations({ cursorPaging: { limit: 20 }, sort: [{ fieldName: "details.startDate", order: "ASC" }] });
|
|
151
158
|
const reservations = (r.reservations ?? []).map(norm);
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
return mockState(s, "empty");
|
|
156
|
-
} catch {
|
|
157
|
-
return mockState(s, "unavailable");
|
|
159
|
+
return settle(s, loaded("reservations", reservations, COPY));
|
|
160
|
+
} catch (err) {
|
|
161
|
+
return settle(s, loadFailed("reservations", err, COPY));
|
|
158
162
|
}
|
|
159
163
|
},
|
|
160
164
|
// Cancel one upcoming reservation. Optimistic (marks it Canceled immediately);
|
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
// himi-branded-lite-reviews —
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
// screen shows a clearly-labelled "Sample content" banner. Real reviews always
|
|
7
|
-
// win the moment any approved review exists.
|
|
1
|
+
// himi-branded-lite-reviews — reads the site's approved Wix Reviews (queryReviews).
|
|
2
|
+
// a failed query is an error with Retry (or Sign in when Wix refuses the
|
|
3
|
+
// visitor) and an empty one is a real empty state — never sample rows presented as
|
|
4
|
+
// the customer's own. Samples appear only in the host's explicit sample preview
|
|
5
|
+
// (_shared/branded-load-state.ts).
|
|
8
6
|
import { defineService } from "../_shared/collection-service.js";
|
|
7
|
+
import { LOADING, loaded, loadFailed, type LoadCopy, type LoadFlags } from "../_shared/branded-load-state.js";
|
|
9
8
|
import { queryReviews, type WixReview } from "@himalaya/wix-reviews";
|
|
10
9
|
|
|
11
10
|
/** `rating` (0–5) feeds the row's Rating control (spoken "N out of 5"); `stars` stays for older descriptors. */
|
|
12
11
|
interface Row { id: string; author: string; stars: string; rating: number; title: string; body: string }
|
|
13
|
-
interface S {
|
|
14
|
-
status: "loading" | "ready";
|
|
12
|
+
interface S extends LoadFlags {
|
|
15
13
|
reviews: Row[]; emptyText: string;
|
|
16
14
|
isMock: boolean; notMock: boolean; /** #2849 — hiddenWhen() hides on TRUE, so these are inverted: the empty-state banner
|
|
17
15
|
* shows only when the site really has none, and the unavailable one only when the
|
|
@@ -48,22 +46,27 @@ const MOCK: Row[] = [
|
|
|
48
46
|
{ id: "sample-4", author: "Amit L.", stars: "★★★★☆", rating: 4, title: "Solid", body: "Good quality and quick service. Would order again." },
|
|
49
47
|
];
|
|
50
48
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
/** sample rows reach the screen ONLY in the host's explicit sample preview;
|
|
50
|
+
* a failed or empty query is an honest error / empty state (branded-load-state.ts). */
|
|
51
|
+
const COPY: LoadCopy<Row> = {
|
|
52
|
+
prefix: "reviews",
|
|
53
|
+
empty: "No reviews yet.",
|
|
54
|
+
error: "Reviews couldn't be loaded.",
|
|
55
|
+
signIn: "Sign in to see reviews.",
|
|
56
|
+
sample: () => MOCK.map((r) => ({ ...r })),
|
|
57
|
+
};
|
|
54
58
|
|
|
55
59
|
const svc = defineService<S, { load: (s: S) => Promise<S> }>("himiBrandedReviews", {
|
|
56
|
-
state: {
|
|
60
|
+
state: { ...LOADING, reviews: [], emptyText: "" },
|
|
57
61
|
actions: {
|
|
58
62
|
load: async (s) => {
|
|
59
63
|
try {
|
|
60
64
|
const r = await queryReviews({ cursorPaging: { limit: 20 } });
|
|
61
65
|
const raw = (r.reviews ?? r.results ?? []) as WixReview[];
|
|
62
66
|
const reviews = raw.map(norm).filter((x) => x.title || x.body);
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
return mockState(s, "unavailable");
|
|
67
|
+
return { ...s, ...loaded("reviews", reviews, COPY) };
|
|
68
|
+
} catch (err) {
|
|
69
|
+
return { ...s, ...loadFailed("reviews", err, COPY) };
|
|
67
70
|
}
|
|
68
71
|
},
|
|
69
72
|
},
|