@wix/himalaya-cli 0.1614.0 → 0.1616.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 +2 -0
- package/package.json +2 -2
- package/template-icons/salon-spa.png +0 -0
- package/templates/beauty-salon/tier5-src/_shared/branded-load-state.ts +5 -2
- package/templates/beauty-salon/tier5-src/_shared/himi-account.ts +31 -0
- package/templates/beauty-salon/tier5-src/_shared/himi-booking-saved.ts +88 -0
- package/templates/beauty-salon/tier5-src/himi-booking-service/index.ts +50 -3
- package/templates/beauty-salon/tier5-src/himi-booking-services/index.ts +70 -3
- package/templates/beauty-salon/tier5-src/himi-booking-time/index.ts +40 -8
- package/templates/beauty-salon/tier5-src/himi-branded-lite-agenda/index.ts +7 -2
- package/templates/branded-lite/tier5-src/_shared/branded-load-state.ts +5 -2
- package/templates/branded-lite/tier5-src/_shared/himi-account.ts +31 -0
- package/templates/branded-lite/tier5-src/_shared/himi-booking-saved.ts +88 -0
- package/templates/branded-lite/tier5-src/himi-booking-service/index.ts +50 -3
- package/templates/branded-lite/tier5-src/himi-booking-services/index.ts +70 -3
- package/templates/branded-lite/tier5-src/himi-booking-time/index.ts +40 -8
- package/templates/branded-lite/tier5-src/himi-branded-lite-agenda/index.ts +7 -2
- package/templates/branded-lite/tier5-src/himi-branded-lite-galleries/index.ts +104 -12
- package/templates/community-club/tier5-src/_shared/branded-load-state.ts +5 -2
- package/templates/community-club/tier5-src/_shared/himi-account.ts +31 -0
- package/templates/events-meetups/tier5-src/_shared/branded-load-state.ts +5 -2
- package/templates/events-meetups/tier5-src/_shared/himi-account.ts +31 -0
- package/templates/gym-fitness/tier5-src/_shared/branded-load-state.ts +5 -2
- package/templates/gym-fitness/tier5-src/_shared/himi-account.ts +31 -0
- package/templates/gym-fitness/tier5-src/_shared/himi-booking-saved.ts +88 -0
- package/templates/gym-fitness/tier5-src/himi-booking-service/index.ts +50 -3
- package/templates/gym-fitness/tier5-src/himi-booking-services/index.ts +70 -3
- package/templates/gym-fitness/tier5-src/himi-booking-time/index.ts +40 -8
- package/templates/gym-fitness/tier5-src/himi-branded-lite-agenda/index.ts +7 -2
- package/templates/nonprofit-cause/tier5-src/_shared/branded-load-state.ts +5 -2
- package/templates/nonprofit-cause/tier5-src/_shared/himi-account.ts +31 -0
- package/templates/podcast-creator/tier5-src/_shared/branded-load-state.ts +5 -2
- package/templates/podcast-creator/tier5-src/_shared/himi-account.ts +31 -0
- package/templates/portfolio-creative/tier5-src/_shared/branded-load-state.ts +5 -2
- package/templates/portfolio-creative/tier5-src/_shared/himi-account.ts +31 -0
- package/templates/restaurant/tier5-src/_shared/branded-load-state.ts +5 -2
- package/templates/restaurant/tier5-src/_shared/himi-account.ts +31 -0
- package/templates/retail-store/tier5-src/_shared/branded-load-state.ts +5 -2
- package/templates/retail-store/tier5-src/_shared/himi-account.ts +31 -0
- package/templates/salon-spa/README.md +53 -0
- package/templates/salon-spa/config.ts +272 -0
- package/templates/salon-spa/dev/index.ts +19893 -0
- package/templates/salon-spa/himalaya.content.json +49 -0
- package/templates/salon-spa/himalaya.template.json +14 -0
- package/templates/salon-spa/icon.png +0 -0
- package/templates/salon-spa/platforms.json +1 -0
- package/templates/salon-spa/tier5-src/_shared/app-locale.ts +61 -0
- package/templates/salon-spa/tier5-src/_shared/booking-location.ts +147 -0
- package/templates/salon-spa/tier5-src/_shared/booking-session.ts +222 -0
- package/templates/salon-spa/tier5-src/_shared/branded-lite-hosted.ts +278 -0
- package/templates/salon-spa/tier5-src/_shared/branded-load-state.ts +109 -0
- package/templates/salon-spa/tier5-src/_shared/business-chat-copy.ts +40 -0
- package/templates/salon-spa/tier5-src/_shared/business-chat-history.ts +48 -0
- package/templates/salon-spa/tier5-src/_shared/business-chat-message-model.ts +177 -0
- package/templates/salon-spa/tier5-src/_shared/business-chat-model.ts +56 -0
- package/templates/salon-spa/tier5-src/_shared/business-chat-presenter.ts +581 -0
- package/templates/salon-spa/tier5-src/_shared/business-chat-transport.ts +148 -0
- package/templates/salon-spa/tier5-src/_shared/collection-contract.ts +230 -0
- package/templates/salon-spa/tier5-src/_shared/collection-query.ts +193 -0
- package/templates/salon-spa/tier5-src/_shared/collection-service.ts +400 -0
- package/templates/salon-spa/tier5-src/_shared/detail-presence.ts +51 -0
- package/templates/salon-spa/tier5-src/_shared/empty-flags.ts +33 -0
- package/templates/salon-spa/tier5-src/_shared/engine-intl.ts +508 -0
- package/templates/salon-spa/tier5-src/_shared/himi-account.ts +164 -0
- package/templates/salon-spa/tier5-src/_shared/himi-booking-saved.ts +88 -0
- package/templates/salon-spa/tier5-src/_shared/himi-bookings.ts +318 -0
- package/templates/salon-spa/tier5-src/_shared/himi-copy.ts +89 -0
- package/templates/salon-spa/tier5-src/_shared/himi-store.ts +7 -0
- package/templates/salon-spa/tier5-src/_shared/himi-text.ts +24 -0
- package/templates/salon-spa/tier5-src/_shared/host-events.ts +66 -0
- package/templates/salon-spa/tier5-src/_shared/hosted-checkout.ts +70 -0
- package/templates/salon-spa/tier5-src/_shared/iap-attendance-form.ts +106 -0
- package/templates/salon-spa/tier5-src/_shared/iap-attendance-purchase.ts +211 -0
- package/templates/salon-spa/tier5-src/_shared/iap-attendance.ts +38 -0
- package/templates/salon-spa/tier5-src/_shared/iap-worker.ts +125 -0
- package/templates/salon-spa/tier5-src/_shared/local-preferences.ts +38 -0
- package/templates/salon-spa/tier5-src/_shared/member-access.ts +52 -0
- package/templates/salon-spa/tier5-src/_shared/member-account-routes.ts +52 -0
- package/templates/salon-spa/tier5-src/_shared/member-bookings.ts +94 -0
- package/templates/salon-spa/tier5-src/_shared/offset-page.ts +10 -0
- package/templates/salon-spa/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/salon-spa/tier5-src/_shared/owner-load-error.ts +348 -0
- package/templates/salon-spa/tier5-src/_shared/payment-setup.ts +6 -0
- package/templates/salon-spa/tier5-src/_shared/rich-body.ts +78 -0
- package/templates/salon-spa/tier5-src/_shared/rich-content-link.ts +34 -0
- package/templates/salon-spa/tier5-src/_shared/weekly-goal.ts +107 -0
- package/templates/salon-spa/tier5-src/_shared/wix-service-price.ts +146 -0
- package/templates/salon-spa/tier5-src/business-chat/index.ts +669 -0
- package/templates/salon-spa/tier5-src/himi-booking-account/index.ts +241 -0
- package/templates/salon-spa/tier5-src/himi-booking-bookings/index.ts +466 -0
- package/templates/salon-spa/tier5-src/himi-booking-saved/index.ts +103 -0
- package/templates/salon-spa/tier5-src/himi-booking-service/index.ts +1170 -0
- package/templates/salon-spa/tier5-src/himi-booking-services/index.ts +791 -0
- package/templates/salon-spa/tier5-src/himi-booking-time/index.ts +1712 -0
- package/templates/salon-spa/tier5-src/himi-branded-lite-agenda/index.ts +950 -0
- package/templates/salon-spa/tier5-src/himi-branded-lite-galleries/index.ts +282 -0
- package/templates/salon-spa/tier5-src/himi-salon-home/index.ts +544 -0
- package/templates/salon-spa/tier5-src/himi-store-account/index.ts +925 -0
- package/templates/salon-spa/tokens.json +341 -0
- package/templates/yoga-studio/tier5-src/_shared/branded-load-state.ts +5 -2
- package/templates/yoga-studio/tier5-src/_shared/himi-account.ts +31 -0
- package/templates/yoga-studio/tier5-src/_shared/himi-booking-saved.ts +88 -0
- package/templates/yoga-studio/tier5-src/himi-booking-service/index.ts +50 -3
- package/templates/yoga-studio/tier5-src/himi-booking-services/index.ts +70 -3
- package/templates/yoga-studio/tier5-src/himi-booking-time/index.ts +40 -8
- package/templates/yoga-studio/tier5-src/himi-branded-lite-agenda/index.ts +7 -2
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
// Tier-5 bundle: himi-booking — visitor/member account state.
|
|
2
|
+
import { defineService } from "@himalaya/state";
|
|
3
|
+
import { dispatch } from "@himalaya/dispatch";
|
|
4
|
+
import { queryBookings, type WixBooking } from "@himalaya/wix-bookings";
|
|
5
|
+
import { loadMemberProfile, strOf, fmtDateTime, titleCase, type AccountActivityRow } from "../_shared/himi-account";
|
|
6
|
+
import { stashCopy, copyParam } from "../_shared/himi-copy.js";
|
|
7
|
+
|
|
8
|
+
interface S {
|
|
9
|
+
status: "loading" | "ready";
|
|
10
|
+
isMember: boolean;
|
|
11
|
+
notMember: boolean;
|
|
12
|
+
identityLine: string;
|
|
13
|
+
detailLine: string;
|
|
14
|
+
memberName: string;
|
|
15
|
+
memberEmail: string;
|
|
16
|
+
memberImage: string;
|
|
17
|
+
memberInitials: string;
|
|
18
|
+
hasMemberImage: boolean;
|
|
19
|
+
noMemberImage: boolean;
|
|
20
|
+
authTitle: string;
|
|
21
|
+
authBody: string;
|
|
22
|
+
email: string;
|
|
23
|
+
password: string;
|
|
24
|
+
firstName: string;
|
|
25
|
+
lastName: string;
|
|
26
|
+
message: string;
|
|
27
|
+
isLoading: boolean;
|
|
28
|
+
notLoading: boolean;
|
|
29
|
+
isRegistering: boolean;
|
|
30
|
+
notRegistering: boolean;
|
|
31
|
+
activityTitle: string;
|
|
32
|
+
activitySummary: string;
|
|
33
|
+
activityRows: AccountActivityRow[];
|
|
34
|
+
activityEmptyText: string;
|
|
35
|
+
hasActivity: boolean;
|
|
36
|
+
noActivity: boolean;
|
|
37
|
+
servicesScreenId: string;
|
|
38
|
+
bookingsScreenId: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function derive(s: S): S {
|
|
42
|
+
const isRegistering = !!s.isRegistering;
|
|
43
|
+
const hasActivity = s.activityRows.length > 0;
|
|
44
|
+
return {
|
|
45
|
+
...s,
|
|
46
|
+
isLoading: s.status === "loading",
|
|
47
|
+
notLoading: s.status !== "loading",
|
|
48
|
+
notMember: !s.isMember,
|
|
49
|
+
isRegistering,
|
|
50
|
+
notRegistering: !isRegistering,
|
|
51
|
+
hasActivity,
|
|
52
|
+
noActivity: !hasActivity,
|
|
53
|
+
authTitle: isRegistering
|
|
54
|
+
? copyParam("bookingAccount.authTitleRegister", "Create account")
|
|
55
|
+
: copyParam("bookingAccount.authTitle", "Welcome"),
|
|
56
|
+
authBody: isRegistering
|
|
57
|
+
? copyParam("bookingAccount.authBodyRegister", "Create a member account to book services and see your history.")
|
|
58
|
+
: copyParam("bookingAccount.authBody", "Sign in to book services and see your history."),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function bookingEmail(booking: WixBooking): string {
|
|
63
|
+
const contact = booking.contactDetails as { email?: string; contactEmail?: string } | undefined;
|
|
64
|
+
return (contact?.email ?? contact?.contactEmail ?? "").toLowerCase();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function bookingTitle(booking: WixBooking): string {
|
|
68
|
+
const entity = booking.bookedEntity as { serviceName?: string; title?: string } | undefined;
|
|
69
|
+
return entity?.serviceName || entity?.title || "Booking";
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function bookingStart(booking: WixBooking): string | undefined {
|
|
73
|
+
const entity = booking.bookedEntity as { slot?: { startDate?: string } } | undefined;
|
|
74
|
+
return entity?.slot?.startDate || booking.startDate || booking.createdDate;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function bookingRow(booking: WixBooking): AccountActivityRow {
|
|
78
|
+
const start = bookingStart(booking);
|
|
79
|
+
return {
|
|
80
|
+
id: booking.id || start || bookingTitle(booking),
|
|
81
|
+
title: bookingTitle(booking),
|
|
82
|
+
subtitle: fmtDateTime(start) || "Booked time",
|
|
83
|
+
meta: titleCase(booking.paymentStatus) || "",
|
|
84
|
+
status: titleCase(booking.status) || "Booked",
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async function bookingRows(memberEmail: string): Promise<AccountActivityRow[]> {
|
|
89
|
+
if (!memberEmail) return [];
|
|
90
|
+
const res = await queryBookings({ query: { paging: { limit: 50 } } });
|
|
91
|
+
return (res.bookings ?? [])
|
|
92
|
+
.filter((booking) => bookingEmail(booking) === memberEmail.toLowerCase())
|
|
93
|
+
.sort((a, b) => (Date.parse(bookingStart(b) || "") || 0) - (Date.parse(bookingStart(a) || "") || 0))
|
|
94
|
+
.slice(0, 3)
|
|
95
|
+
.map(bookingRow);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function probe(s: S): Promise<S> {
|
|
99
|
+
const profile = await loadMemberProfile(copyParam("bookingAccount.guestDetail", "Sign in to book services and see your booking history."));
|
|
100
|
+
let activityRows: AccountActivityRow[] = [];
|
|
101
|
+
if (profile.isMember) {
|
|
102
|
+
try {
|
|
103
|
+
activityRows = await bookingRows(profile.memberEmail);
|
|
104
|
+
} catch {
|
|
105
|
+
activityRows = [];
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return derive({
|
|
109
|
+
...s,
|
|
110
|
+
status: "ready",
|
|
111
|
+
isMember: profile.isMember,
|
|
112
|
+
identityLine: profile.identityLine,
|
|
113
|
+
detailLine: profile.detailLine,
|
|
114
|
+
memberName: profile.memberName,
|
|
115
|
+
memberEmail: profile.memberEmail,
|
|
116
|
+
memberImage: profile.memberImage,
|
|
117
|
+
memberInitials: profile.memberInitials,
|
|
118
|
+
hasMemberImage: profile.hasMemberImage,
|
|
119
|
+
noMemberImage: profile.noMemberImage,
|
|
120
|
+
email: profile.memberEmail || s.email,
|
|
121
|
+
message: "",
|
|
122
|
+
activityRows,
|
|
123
|
+
activityTitle: copyParam("bookingAccount.activityTitle", "Recent bookings"),
|
|
124
|
+
activitySummary: activityRows.length
|
|
125
|
+
? `${activityRows.length} recent ${activityRows.length === 1 ? "booking" : "bookings"}`
|
|
126
|
+
: copyParam("bookingAccount.activityHint", "Bookings are loaded from Wix Bookings."),
|
|
127
|
+
activityEmptyText: profile.isMember
|
|
128
|
+
? copyParam("bookingAccount.activityEmptyMember", "No bookings for this member yet.")
|
|
129
|
+
: copyParam("bookingAccount.activityEmptyGuest", "Sign in to see bookings."),
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function optimisticMember(s: S, email: string): S {
|
|
134
|
+
return derive({
|
|
135
|
+
...s,
|
|
136
|
+
status: "ready",
|
|
137
|
+
isMember: true,
|
|
138
|
+
identityLine: copyParam("bookingAccount.signedIn", "Signed in"),
|
|
139
|
+
detailLine: email,
|
|
140
|
+
memberName: email,
|
|
141
|
+
memberEmail: email,
|
|
142
|
+
memberImage: "",
|
|
143
|
+
memberInitials: "M",
|
|
144
|
+
hasMemberImage: false,
|
|
145
|
+
noMemberImage: true,
|
|
146
|
+
email,
|
|
147
|
+
password: "",
|
|
148
|
+
firstName: "",
|
|
149
|
+
lastName: "",
|
|
150
|
+
isRegistering: false,
|
|
151
|
+
message: "",
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const svc = defineService<S, {
|
|
156
|
+
load: (s: S, arg?: unknown) => Promise<S>;
|
|
157
|
+
refresh: (s: S, arg?: unknown) => Promise<S>;
|
|
158
|
+
setEmail: (s: S, arg?: unknown) => S;
|
|
159
|
+
setPassword: (s: S, arg?: unknown) => S;
|
|
160
|
+
setFirstName: (s: S, arg?: unknown) => S;
|
|
161
|
+
setLastName: (s: S, arg?: unknown) => S;
|
|
162
|
+
showRegister: (s: S) => S;
|
|
163
|
+
showSignIn: (s: S) => S;
|
|
164
|
+
signIn: (s: S) => Promise<S>;
|
|
165
|
+
register: (s: S) => Promise<S>;
|
|
166
|
+
signOut: (s: S) => Promise<S>;
|
|
167
|
+
}>("himiBookingAccount", {
|
|
168
|
+
state: derive({
|
|
169
|
+
status: "loading",
|
|
170
|
+
isMember: false,
|
|
171
|
+
notMember: true,
|
|
172
|
+
identityLine: "",
|
|
173
|
+
detailLine: "",
|
|
174
|
+
memberName: "",
|
|
175
|
+
memberEmail: "",
|
|
176
|
+
memberImage: "",
|
|
177
|
+
memberInitials: "M",
|
|
178
|
+
hasMemberImage: false,
|
|
179
|
+
noMemberImage: true,
|
|
180
|
+
authTitle: "Welcome",
|
|
181
|
+
authBody: "Sign in to book services and see your history.",
|
|
182
|
+
email: "",
|
|
183
|
+
password: "",
|
|
184
|
+
firstName: "",
|
|
185
|
+
lastName: "",
|
|
186
|
+
message: "",
|
|
187
|
+
isLoading: true,
|
|
188
|
+
notLoading: false,
|
|
189
|
+
isRegistering: false,
|
|
190
|
+
notRegistering: true,
|
|
191
|
+
activityTitle: "Recent bookings",
|
|
192
|
+
activitySummary: "",
|
|
193
|
+
activityRows: [],
|
|
194
|
+
activityEmptyText: "No bookings for this member yet.",
|
|
195
|
+
hasActivity: false,
|
|
196
|
+
noActivity: true,
|
|
197
|
+
servicesScreenId: "himi_services",
|
|
198
|
+
bookingsScreenId: "himi_bookings",
|
|
199
|
+
}),
|
|
200
|
+
actions: {
|
|
201
|
+
load: (s, arg) => { stashCopy(arg); return probe(s); },
|
|
202
|
+
refresh: (s, arg) => { stashCopy(arg); return probe(s); },
|
|
203
|
+
setEmail: (s, arg) => derive({ ...s, email: strOf(arg), message: "" }),
|
|
204
|
+
setPassword: (s, arg) => derive({ ...s, password: strOf(arg), message: "" }),
|
|
205
|
+
setFirstName: (s, arg) => derive({ ...s, firstName: strOf(arg), message: "" }),
|
|
206
|
+
setLastName: (s, arg) => derive({ ...s, lastName: strOf(arg), message: "" }),
|
|
207
|
+
showRegister: (s) => derive({ ...s, isRegistering: true, message: "" }),
|
|
208
|
+
showSignIn: (s) => derive({ ...s, isRegistering: false, message: "" }),
|
|
209
|
+
signIn: async (s) => {
|
|
210
|
+
if (!s.email || !s.password) return derive({ ...s, message: copyParam("bookingAccount.validationEmailPassword", "Enter your email and password.") });
|
|
211
|
+
try {
|
|
212
|
+
await dispatch("himi.wix.signInDirect", { email: s.email, password: s.password });
|
|
213
|
+
const next = await probe(optimisticMember(s, s.email));
|
|
214
|
+
return derive({ ...next, password: "", message: next.isMember ? "" : copyParam("bookingAccount.signInCheckDetails", "Sign in failed. Check your details.") });
|
|
215
|
+
} catch {
|
|
216
|
+
return derive({ ...s, password: "", message: copyParam("bookingAccount.signInFailed", "Sign in failed. Try again.") });
|
|
217
|
+
}
|
|
218
|
+
},
|
|
219
|
+
register: async (s) => {
|
|
220
|
+
if (!s.email || !s.password) return derive({ ...s, message: copyParam("bookingAccount.validationEmailPassword", "Enter your email and password.") });
|
|
221
|
+
try {
|
|
222
|
+
await dispatch("himi.wix.registerDirect", {
|
|
223
|
+
email: s.email,
|
|
224
|
+
password: s.password,
|
|
225
|
+
firstName: s.firstName,
|
|
226
|
+
lastName: s.lastName,
|
|
227
|
+
});
|
|
228
|
+
const next = await probe(optimisticMember(s, s.email));
|
|
229
|
+
return derive({ ...next, password: "", message: next.isMember ? "" : copyParam("bookingAccount.registerTrySignIn", "Account creation failed. Try signing in.") });
|
|
230
|
+
} catch {
|
|
231
|
+
return derive({ ...s, password: "", message: copyParam("bookingAccount.registerFailed", "Account creation failed. Try another email.") });
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
signOut: async (s) => {
|
|
235
|
+
try { await dispatch("himi.wix.signOut"); } catch { /* ignore */ }
|
|
236
|
+
return probe({ ...s, isMember: false, isRegistering: false, message: "" });
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
});
|
|
240
|
+
svc.load();
|
|
241
|
+
export { svc };
|