@juo/blocks 1.1.0-alpha.4 → 1.1.0-alpha.6
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/core.js +546 -504
- package/dist/services/customer/adapter.d.ts +1 -6
- package/dist/services/customer/adapter.d.ts.map +1 -1
- package/dist/services/customer/customerService.d.ts +3 -3
- package/dist/services/customer/customerService.d.ts.map +1 -1
- package/dist/services/customer/index.d.ts +2 -1
- package/dist/services/customer/index.d.ts.map +1 -1
- package/dist/services/customer/types.d.ts +2 -1
- package/dist/services/customer/types.d.ts.map +1 -1
- package/dist/services/login/adapter.d.ts +32 -0
- package/dist/services/login/adapter.d.ts.map +1 -0
- package/dist/services/login/index.d.ts +2 -1
- package/dist/services/login/index.d.ts.map +1 -1
- package/dist/services/login/loginService.d.ts +4 -2
- package/dist/services/login/loginService.d.ts.map +1 -1
- package/dist/services/order/adapter.d.ts +1 -4
- package/dist/services/order/adapter.d.ts.map +1 -1
- package/dist/services/order/orderService.d.ts.map +1 -1
- package/dist/services/order/types.d.ts +0 -4
- package/dist/services/order/types.d.ts.map +1 -1
- package/dist/services/product/adapter.d.ts +4 -1
- package/dist/services/product/adapter.d.ts.map +1 -1
- package/dist/services/product/index.d.ts +1 -1
- package/dist/services/product/index.d.ts.map +1 -1
- package/dist/services/schedules/adapter.d.ts +2 -0
- package/dist/services/schedules/adapter.d.ts.map +1 -1
- package/dist/services/schedules/types.d.ts +2 -0
- package/dist/services/schedules/types.d.ts.map +1 -1
- package/dist/services/subscription/adapter.d.ts +0 -7
- package/dist/services/subscription/adapter.d.ts.map +1 -1
- package/dist/services/subscription/subscriptionService.d.ts +0 -4
- package/dist/services/subscription/subscriptionService.d.ts.map +1 -1
- package/dist/services/subscription/types.d.ts +8 -15
- package/dist/services/subscription/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/core.js
CHANGED
|
@@ -155,6 +155,122 @@ function uuid() {
|
|
|
155
155
|
(c2) => (c2 ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c2 / 4).toString(16)
|
|
156
156
|
);
|
|
157
157
|
}
|
|
158
|
+
function createMockLoginAdapter() {
|
|
159
|
+
return {
|
|
160
|
+
async passwordlessStart() {
|
|
161
|
+
return { _tag: "Success", data: void 0 };
|
|
162
|
+
},
|
|
163
|
+
async authenticate() {
|
|
164
|
+
return {
|
|
165
|
+
_tag: "Success",
|
|
166
|
+
data: {
|
|
167
|
+
access_token: "mock-access-token",
|
|
168
|
+
refresh_token: "mock-refresh-token",
|
|
169
|
+
expires_in: 3600
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
},
|
|
173
|
+
getAuthorizeUrl({ connection, state, shop, appUrl }) {
|
|
174
|
+
const url = new URL(`${appUrl}/auth/customer/authorize`);
|
|
175
|
+
url.searchParams.set("connection", connection);
|
|
176
|
+
url.searchParams.set("state", state);
|
|
177
|
+
url.searchParams.set("shop", shop);
|
|
178
|
+
return url.toString();
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
function createApiLoginAdapter(fetcher, opts) {
|
|
183
|
+
const { shopDomain, appUrl } = opts;
|
|
184
|
+
async function callAuthEndpoint(path, body, lang) {
|
|
185
|
+
const url = lang ? `${path}?lang=${lang}` : path;
|
|
186
|
+
const res = await fetcher(url, {
|
|
187
|
+
method: "POST",
|
|
188
|
+
headers: {
|
|
189
|
+
Accept: "application/json",
|
|
190
|
+
"Content-Type": "application/json",
|
|
191
|
+
"X-Shopify-Shop-Domain": shopDomain
|
|
192
|
+
},
|
|
193
|
+
body: JSON.stringify(body)
|
|
194
|
+
});
|
|
195
|
+
if (res.status === 403) {
|
|
196
|
+
const data = await res.json();
|
|
197
|
+
if ("error_description" in data) {
|
|
198
|
+
if (data.error_description === "Wrong email or verification code.") {
|
|
199
|
+
throw new AuthenticationError(AuthenticationErrorReason.IncorrectCode);
|
|
200
|
+
} else if (data.error_description === "You've reached the maximum number of attempts. Please try to login again.") {
|
|
201
|
+
throw new AuthenticationError(AuthenticationErrorReason.TooManyTries);
|
|
202
|
+
} else if (data.error_description === "The verification code has expired. Please try to login again.") {
|
|
203
|
+
throw new AuthenticationError(AuthenticationErrorReason.Expired);
|
|
204
|
+
}
|
|
205
|
+
} else if ("code" in data && data.code === "AUTH_ERROR") {
|
|
206
|
+
throw new AuthenticationError(AuthenticationErrorReason.NoEmail, {
|
|
207
|
+
connection: data.connection
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
if (!res.ok) {
|
|
212
|
+
throw new Error(`Unexpected response: ${res.statusText}`);
|
|
213
|
+
}
|
|
214
|
+
return { _tag: "Success", data: void 0 };
|
|
215
|
+
}
|
|
216
|
+
return {
|
|
217
|
+
async passwordlessStart({ email, lang }) {
|
|
218
|
+
try {
|
|
219
|
+
await callAuthEndpoint(
|
|
220
|
+
"/auth/customer/passwordless/start",
|
|
221
|
+
{ email },
|
|
222
|
+
lang
|
|
223
|
+
);
|
|
224
|
+
return { _tag: "Success", data: void 0 };
|
|
225
|
+
} catch (e2) {
|
|
226
|
+
return { _tag: "Failure", error: e2 };
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
async authenticate(params) {
|
|
230
|
+
try {
|
|
231
|
+
const res = await fetcher("/auth/customer/token", {
|
|
232
|
+
method: "POST",
|
|
233
|
+
headers: {
|
|
234
|
+
Accept: "application/json",
|
|
235
|
+
"Content-Type": "application/json",
|
|
236
|
+
"X-Shopify-Shop-Domain": shopDomain
|
|
237
|
+
},
|
|
238
|
+
body: JSON.stringify(params)
|
|
239
|
+
});
|
|
240
|
+
if (res.status === 403) {
|
|
241
|
+
const data = await res.json();
|
|
242
|
+
if ("error_description" in data) {
|
|
243
|
+
if (data.error_description === "Wrong email or verification code.") {
|
|
244
|
+
throw new AuthenticationError(AuthenticationErrorReason.IncorrectCode);
|
|
245
|
+
} else if (data.error_description === "You've reached the maximum number of attempts. Please try to login again.") {
|
|
246
|
+
throw new AuthenticationError(AuthenticationErrorReason.TooManyTries);
|
|
247
|
+
} else if (data.error_description === "The verification code has expired. Please try to login again.") {
|
|
248
|
+
throw new AuthenticationError(AuthenticationErrorReason.Expired);
|
|
249
|
+
}
|
|
250
|
+
} else if ("code" in data && data.code === "AUTH_ERROR") {
|
|
251
|
+
throw new AuthenticationError(AuthenticationErrorReason.NoEmail, {
|
|
252
|
+
connection: data.connection
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
if (!res.ok) {
|
|
257
|
+
throw new Error(`Unexpected response: ${res.statusText}`);
|
|
258
|
+
}
|
|
259
|
+
return { _tag: "Success", data: await res.json() };
|
|
260
|
+
} catch (e2) {
|
|
261
|
+
return { _tag: "Failure", error: e2 };
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
getAuthorizeUrl({ connection, state, shop }) {
|
|
265
|
+
const url = new URL(`${appUrl}/auth/customer/authorize`);
|
|
266
|
+
url.searchParams.set("connection", connection);
|
|
267
|
+
url.searchParams.set("state", state);
|
|
268
|
+
url.searchParams.set("shop", shop);
|
|
269
|
+
return url.toString();
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
const __vite_import_meta_env__ = {};
|
|
158
274
|
var AuthenticationErrorReason = /* @__PURE__ */ ((AuthenticationErrorReason2) => {
|
|
159
275
|
AuthenticationErrorReason2["Expired"] = "expired";
|
|
160
276
|
AuthenticationErrorReason2["IncorrectCode"] = "wrong-code";
|
|
@@ -173,6 +289,9 @@ class AuthenticationError extends Error {
|
|
|
173
289
|
this.data = data ?? {};
|
|
174
290
|
}
|
|
175
291
|
}
|
|
292
|
+
const STORAGE_DELEGATED_TOKEN = "delegated-token";
|
|
293
|
+
const STORAGE_REFRESH_TOKEN_KEY = "refresh-token";
|
|
294
|
+
const STORAGE_STATE_KEY = "state";
|
|
176
295
|
function storage(key, value) {
|
|
177
296
|
const storageKey = `auth:${key}`;
|
|
178
297
|
try {
|
|
@@ -188,83 +307,33 @@ function storage(key, value) {
|
|
|
188
307
|
}
|
|
189
308
|
return null;
|
|
190
309
|
}
|
|
191
|
-
const STORAGE_DELEGATED_TOKEN = "delegated-token";
|
|
192
|
-
const STORAGE_REFRESH_TOKEN_KEY = "refresh-token";
|
|
193
|
-
const STORAGE_STATE_KEY = "state";
|
|
194
|
-
function createAuthFunctions(basePath, shop) {
|
|
195
|
-
async function start(email, lang) {
|
|
196
|
-
const response = await fetch(
|
|
197
|
-
`${basePath}/auth/customer/passwordless/start?lang=${lang}`,
|
|
198
|
-
{
|
|
199
|
-
method: "POST",
|
|
200
|
-
headers: {
|
|
201
|
-
Accept: "application/json",
|
|
202
|
-
"Content-Type": "application/json",
|
|
203
|
-
"X-Shopify-Shop-Domain": shop
|
|
204
|
-
},
|
|
205
|
-
body: JSON.stringify({ email })
|
|
206
|
-
}
|
|
207
|
-
);
|
|
208
|
-
if (response.status !== 200) {
|
|
209
|
-
throw new Error(`Unexpected response: ${response.statusText}`);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
async function authenticate(data) {
|
|
213
|
-
const response = await fetch(`${basePath}/auth/customer/token`, {
|
|
214
|
-
method: "POST",
|
|
215
|
-
headers: {
|
|
216
|
-
Accept: "application/json",
|
|
217
|
-
"Content-Type": "application/json",
|
|
218
|
-
"X-Shopify-Shop-Domain": shop
|
|
219
|
-
},
|
|
220
|
-
body: JSON.stringify(data)
|
|
221
|
-
});
|
|
222
|
-
if (response.status === 403) {
|
|
223
|
-
const data2 = await response.json();
|
|
224
|
-
if ("error_description" in data2) {
|
|
225
|
-
if (data2.error_description === "Wrong email or verification code.") {
|
|
226
|
-
throw new AuthenticationError(
|
|
227
|
-
"wrong-code"
|
|
228
|
-
/* IncorrectCode */
|
|
229
|
-
);
|
|
230
|
-
} else if (data2.error_description === "You've reached the maximum number of attempts. Please try to login again.") {
|
|
231
|
-
throw new AuthenticationError(
|
|
232
|
-
"too-many-tries"
|
|
233
|
-
/* TooManyTries */
|
|
234
|
-
);
|
|
235
|
-
} else if (data2.error_description === "The verification code has expired. Please try to login again.") {
|
|
236
|
-
throw new AuthenticationError(
|
|
237
|
-
"expired"
|
|
238
|
-
/* Expired */
|
|
239
|
-
);
|
|
240
|
-
}
|
|
241
|
-
} else if ("code" in data2) {
|
|
242
|
-
if (data2.code === "AUTH_ERROR") {
|
|
243
|
-
throw new AuthenticationError("no-email", {
|
|
244
|
-
connection: data2.connection
|
|
245
|
-
});
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
if (response.status !== 200) {
|
|
250
|
-
throw new Error(`Unexpected response: ${response.statusText}`);
|
|
251
|
-
}
|
|
252
|
-
return await response.json();
|
|
253
|
-
}
|
|
254
|
-
return { start, authenticate };
|
|
255
|
-
}
|
|
256
310
|
function nonce(len = 10) {
|
|
257
311
|
return uuid().replace(/-/g, "").slice(0, len);
|
|
258
312
|
}
|
|
259
|
-
function
|
|
260
|
-
const
|
|
313
|
+
function loginService(deps) {
|
|
314
|
+
const apiBase = deps.shop.rootUrl.replace(/\/$/, "") + "/api";
|
|
315
|
+
const appUrl = (typeof import.meta !== "undefined" ? __vite_import_meta_env__ == null ? void 0 : __vite_import_meta_env__.VITE_APP_URL : void 0) ?? "https://admin.juo.io";
|
|
316
|
+
const fetcher = (path, init) => fetch(`${apiBase}${path}`, init);
|
|
317
|
+
const adapter = createApiLoginAdapter(fetcher, {
|
|
318
|
+
shopDomain: deps.shop.domain,
|
|
319
|
+
appUrl
|
|
320
|
+
});
|
|
321
|
+
return createLoginService({
|
|
322
|
+
adapter,
|
|
323
|
+
router: deps.router,
|
|
324
|
+
formatError: deps.formatError,
|
|
325
|
+
shop: {
|
|
326
|
+
domain: deps.shop.domain,
|
|
327
|
+
locale: w(() => deps.getLocale())
|
|
328
|
+
},
|
|
329
|
+
onLoginSuccess: deps.onLoginSuccess
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
function createLoginService(init) {
|
|
333
|
+
const { adapter, formatError, router, shop, onLoginSuccess } = init;
|
|
261
334
|
const accessToken = d(null);
|
|
262
|
-
const delegatedToken = d(
|
|
263
|
-
|
|
264
|
-
);
|
|
265
|
-
const refreshToken = d(
|
|
266
|
-
storage(STORAGE_REFRESH_TOKEN_KEY)
|
|
267
|
-
);
|
|
335
|
+
const delegatedToken = d(storage(STORAGE_DELEGATED_TOKEN));
|
|
336
|
+
const refreshToken = d(storage(STORAGE_REFRESH_TOKEN_KEY));
|
|
268
337
|
const expires = d(null);
|
|
269
338
|
const state = d(storage(STORAGE_STATE_KEY));
|
|
270
339
|
E(() => {
|
|
@@ -276,67 +345,28 @@ function createAuthService(apiUrl, shopDomain) {
|
|
|
276
345
|
E(() => {
|
|
277
346
|
storage(STORAGE_STATE_KEY, state.value);
|
|
278
347
|
});
|
|
279
|
-
function
|
|
348
|
+
function storeTokens(data) {
|
|
280
349
|
const { access_token, refresh_token, expires_in } = data;
|
|
281
350
|
accessToken.value = access_token;
|
|
282
351
|
refreshToken.value = refresh_token;
|
|
283
352
|
expires.value = new Date(Date.now() + expires_in);
|
|
284
353
|
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
},
|
|
293
|
-
getDelegatedToken() {
|
|
294
|
-
return delegatedToken.value;
|
|
295
|
-
},
|
|
296
|
-
setDelegatedToken(token) {
|
|
297
|
-
delegatedToken.value = token;
|
|
298
|
-
},
|
|
299
|
-
async getToken() {
|
|
300
|
-
if (refreshToken.value == null) {
|
|
301
|
-
return null;
|
|
302
|
-
}
|
|
303
|
-
if (accessToken.value == null || typeof accessToken.value === "string" && (expires.value == null || expires.value < /* @__PURE__ */ new Date())) {
|
|
304
|
-
accessToken.value = new Promise(
|
|
305
|
-
(resolve, reject) => authAuthenticate({ refreshToken: refreshToken.value }).then((data) => data).then((data) => {
|
|
306
|
-
store(data);
|
|
307
|
-
resolve(data.access_token);
|
|
354
|
+
async function getToken() {
|
|
355
|
+
if (refreshToken.value == null) return null;
|
|
356
|
+
if (accessToken.value == null || typeof accessToken.value === "string" && (expires.value == null || expires.value < /* @__PURE__ */ new Date())) {
|
|
357
|
+
accessToken.value = new Promise(
|
|
358
|
+
(resolve, reject) => adapter.authenticate({ refreshToken: refreshToken.value }).then((result) => {
|
|
359
|
+
if (result._tag === "Failure") {
|
|
360
|
+
reject(result.error);
|
|
308
361
|
return;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
refreshToken.value = null;
|
|
318
|
-
expires.value = null;
|
|
319
|
-
},
|
|
320
|
-
isAuthenticated: w(
|
|
321
|
-
() => delegatedToken.value != null || refreshToken.value != null
|
|
322
|
-
)
|
|
323
|
-
};
|
|
324
|
-
}
|
|
325
|
-
function loginService(deps) {
|
|
326
|
-
return createLoginService({
|
|
327
|
-
apiUrl: `${deps.shop.rootUrl.replace(/\/$/, "")}/api`,
|
|
328
|
-
router: deps.router,
|
|
329
|
-
formatError: deps.formatError,
|
|
330
|
-
shop: {
|
|
331
|
-
domain: deps.shop.domain,
|
|
332
|
-
locale: w(() => deps.getLocale())
|
|
333
|
-
},
|
|
334
|
-
onLoginSuccess: deps.onLoginSuccess
|
|
335
|
-
});
|
|
336
|
-
}
|
|
337
|
-
function createLoginService(init) {
|
|
338
|
-
const { formatError, router, shop, onLoginSuccess } = init;
|
|
339
|
-
const auth = createAuthService(init.apiUrl.replace(/\/$/, ""), shop.domain);
|
|
362
|
+
}
|
|
363
|
+
storeTokens(result.data);
|
|
364
|
+
resolve(result.data.access_token);
|
|
365
|
+
}).catch(reject)
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
return Promise.resolve(accessToken.value);
|
|
369
|
+
}
|
|
340
370
|
const userEmail = d(null);
|
|
341
371
|
async function onSuccess(query) {
|
|
342
372
|
await (onLoginSuccess == null ? void 0 : onLoginSuccess());
|
|
@@ -349,13 +379,9 @@ function createLoginService(init) {
|
|
|
349
379
|
queryParams[key] = value;
|
|
350
380
|
}
|
|
351
381
|
});
|
|
352
|
-
router.push({
|
|
353
|
-
path: decodeURIComponent(redirect),
|
|
354
|
-
query: queryParams
|
|
355
|
-
});
|
|
382
|
+
router.push({ path: decodeURIComponent(redirect), query: queryParams });
|
|
356
383
|
} else {
|
|
357
|
-
|
|
358
|
-
router.replace(decodeURIComponent(redirect));
|
|
384
|
+
router.replace(decodeURIComponent(query.get(PARAMS.REDIRECT_TO)));
|
|
359
385
|
}
|
|
360
386
|
} else {
|
|
361
387
|
router.replace("/");
|
|
@@ -367,16 +393,17 @@ function createLoginService(init) {
|
|
|
367
393
|
async start(email) {
|
|
368
394
|
try {
|
|
369
395
|
userEmail.value = email;
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
396
|
+
const lang = shop.locale instanceof u ? shop.locale.value : shop.locale;
|
|
397
|
+
const result = await adapter.passwordlessStart({
|
|
398
|
+
email: userEmail.value,
|
|
399
|
+
lang
|
|
400
|
+
});
|
|
401
|
+
if (result._tag === "Failure") {
|
|
402
|
+
return { _tag: "Failure", error: formatError(result.error) };
|
|
403
|
+
}
|
|
374
404
|
return { _tag: "Success", data: void 0 };
|
|
375
405
|
} catch (error) {
|
|
376
|
-
return {
|
|
377
|
-
_tag: "Failure",
|
|
378
|
-
error: formatError(error)
|
|
379
|
-
};
|
|
406
|
+
return { _tag: "Failure", error: formatError(error) };
|
|
380
407
|
}
|
|
381
408
|
},
|
|
382
409
|
async verify(email, code) {
|
|
@@ -387,63 +414,61 @@ function createLoginService(init) {
|
|
|
387
414
|
};
|
|
388
415
|
}
|
|
389
416
|
try {
|
|
390
|
-
const result = await
|
|
417
|
+
const result = await adapter.authenticate({
|
|
391
418
|
email: userEmail.value,
|
|
392
419
|
code
|
|
393
420
|
});
|
|
421
|
+
if (result._tag === "Failure") {
|
|
422
|
+
return { _tag: "Failure", error: formatError(result.error) };
|
|
423
|
+
}
|
|
424
|
+
storeTokens(result.data);
|
|
394
425
|
await onSuccess();
|
|
395
|
-
return { _tag: "Success", data:
|
|
426
|
+
return { _tag: "Success", data: void 0 };
|
|
396
427
|
} catch (error) {
|
|
397
|
-
return {
|
|
398
|
-
_tag: "Failure",
|
|
399
|
-
error: formatError(error)
|
|
400
|
-
};
|
|
428
|
+
return { _tag: "Failure", error: formatError(error) };
|
|
401
429
|
}
|
|
402
430
|
}
|
|
403
431
|
}
|
|
404
432
|
},
|
|
405
433
|
social: {
|
|
406
434
|
async start(provider) {
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
provider === "Facebook" ? "facebook" : "google-oauth2",
|
|
420
|
-
shop.domain
|
|
421
|
-
);
|
|
422
|
-
return {
|
|
423
|
-
_tag: "Success",
|
|
424
|
-
data: void 0
|
|
425
|
-
};
|
|
435
|
+
state.value = nonce();
|
|
436
|
+
const connection = provider === "Facebook" ? "facebook" : "google-oauth2";
|
|
437
|
+
window.location.href = adapter.getAuthorizeUrl({
|
|
438
|
+
connection,
|
|
439
|
+
state: state.value ?? "",
|
|
440
|
+
shop: shop.domain,
|
|
441
|
+
appUrl: (
|
|
442
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
443
|
+
(typeof import.meta !== "undefined" ? __vite_import_meta_env__ == null ? void 0 : __vite_import_meta_env__.VITE_APP_URL : void 0) ?? "https://admin.juo.io"
|
|
444
|
+
)
|
|
445
|
+
});
|
|
446
|
+
return { _tag: "Success", data: void 0 };
|
|
426
447
|
},
|
|
427
448
|
async verify(code) {
|
|
428
449
|
try {
|
|
429
|
-
const result = await
|
|
450
|
+
const result = await adapter.authenticate({ code });
|
|
451
|
+
if (result._tag === "Failure") {
|
|
452
|
+
return { _tag: "Failure", error: formatError(result.error) };
|
|
453
|
+
}
|
|
454
|
+
storeTokens(result.data);
|
|
430
455
|
await onSuccess();
|
|
431
|
-
return { _tag: "Success", data:
|
|
456
|
+
return { _tag: "Success", data: void 0 };
|
|
432
457
|
} catch (error) {
|
|
433
|
-
return {
|
|
434
|
-
_tag: "Failure",
|
|
435
|
-
error: formatError(error)
|
|
436
|
-
};
|
|
458
|
+
return { _tag: "Failure", error: formatError(error) };
|
|
437
459
|
}
|
|
438
460
|
}
|
|
439
461
|
},
|
|
440
462
|
async logout() {
|
|
441
|
-
|
|
463
|
+
accessToken.value = null;
|
|
464
|
+
delegatedToken.value = null;
|
|
465
|
+
refreshToken.value = null;
|
|
466
|
+
expires.value = null;
|
|
442
467
|
return { _tag: "Success", data: void 0 };
|
|
443
468
|
},
|
|
444
469
|
async handleQueryParams(query) {
|
|
445
470
|
if (query.has(PARAMS.DELETGATED_TOKEN)) {
|
|
446
|
-
|
|
471
|
+
delegatedToken.value = query.get(PARAMS.DELETGATED_TOKEN);
|
|
447
472
|
await onSuccess(query);
|
|
448
473
|
return { _tag: "Success", data: void 0 };
|
|
449
474
|
}
|
|
@@ -455,16 +480,13 @@ function createLoginService(init) {
|
|
|
455
480
|
}
|
|
456
481
|
const code = query.get(PARAMS.CODE);
|
|
457
482
|
if (code != null) {
|
|
458
|
-
if (query.get(PARAMS.STATE) !==
|
|
459
|
-
return {
|
|
460
|
-
_tag: "Failure",
|
|
461
|
-
error: formatError("Invalid state")
|
|
462
|
-
};
|
|
483
|
+
if (query.get(PARAMS.STATE) !== state.value) {
|
|
484
|
+
return { _tag: "Failure", error: formatError("Invalid state") };
|
|
463
485
|
} else {
|
|
464
486
|
return service.social.verify(code);
|
|
465
487
|
}
|
|
466
488
|
}
|
|
467
|
-
if (query.get(PARAMS.REFRESH) === "1" && await
|
|
489
|
+
if (query.get(PARAMS.REFRESH) === "1" && await getToken() != null) {
|
|
468
490
|
await onSuccess();
|
|
469
491
|
return { _tag: "Success", data: void 0 };
|
|
470
492
|
}
|
|
@@ -481,14 +503,15 @@ function createLoginService(init) {
|
|
|
481
503
|
}
|
|
482
504
|
return { _tag: "Success", data: void 0 };
|
|
483
505
|
},
|
|
484
|
-
isAuthenticated:
|
|
485
|
-
|
|
506
|
+
isAuthenticated: w(
|
|
507
|
+
() => delegatedToken.value != null || refreshToken.value != null
|
|
508
|
+
),
|
|
509
|
+
getToken,
|
|
486
510
|
async getAuthHeaders() {
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
return { "X-Delegated-Token": delegated };
|
|
511
|
+
if (delegatedToken.value) {
|
|
512
|
+
return { "X-Delegated-Token": delegatedToken.value };
|
|
490
513
|
}
|
|
491
|
-
const token = await
|
|
514
|
+
const token = await getToken();
|
|
492
515
|
if (token) {
|
|
493
516
|
return { Authorization: `Bearer ${token}` };
|
|
494
517
|
}
|
|
@@ -678,6 +701,106 @@ function createMockProductAdapter() {
|
|
|
678
701
|
}
|
|
679
702
|
};
|
|
680
703
|
}
|
|
704
|
+
function mapVariant(variant, currencyCode) {
|
|
705
|
+
var _a;
|
|
706
|
+
return {
|
|
707
|
+
id: variant.id,
|
|
708
|
+
title: variant.title,
|
|
709
|
+
image: variant.image == null ? null : { url: variant.image.url, altText: variant.image.altText ?? void 0 },
|
|
710
|
+
price: { amount: variant.price.toFixed(2), currencyCode },
|
|
711
|
+
...((_a = variant.purchaseOptions) == null ? void 0 : _a.length) ? {
|
|
712
|
+
purchaseOptions: variant.purchaseOptions.map((opt) => ({
|
|
713
|
+
name: opt.name,
|
|
714
|
+
price: { amount: opt.price.toFixed(2), currencyCode },
|
|
715
|
+
interval: opt.interval
|
|
716
|
+
}))
|
|
717
|
+
} : {}
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
function mapProduct(product, currencyCode) {
|
|
721
|
+
return {
|
|
722
|
+
id: product.id,
|
|
723
|
+
title: product.title,
|
|
724
|
+
featuredImage: product.image == null ? null : { url: product.image.url, altText: product.image.altText ?? void 0 },
|
|
725
|
+
hasOnlyDefaultVariant: product.variants.length <= 1,
|
|
726
|
+
variants: {
|
|
727
|
+
items: product.variants.map((v2) => mapVariant(v2, currencyCode)),
|
|
728
|
+
pageInfo: {
|
|
729
|
+
hasNextPage: false,
|
|
730
|
+
hasPrevPage: false,
|
|
731
|
+
startCursor: null,
|
|
732
|
+
endCursor: null
|
|
733
|
+
}
|
|
734
|
+
},
|
|
735
|
+
collections: product.collections
|
|
736
|
+
};
|
|
737
|
+
}
|
|
738
|
+
function createApiProductAdapter(fetcher, opts = { currencyCode: "USD" }) {
|
|
739
|
+
const { currencyCode } = opts;
|
|
740
|
+
async function fetchProducts(params) {
|
|
741
|
+
const query = params.toString() ? `?${params.toString()}` : "";
|
|
742
|
+
const res = await fetcher(`/customer/v1/products${query}`);
|
|
743
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
744
|
+
return res.json();
|
|
745
|
+
}
|
|
746
|
+
return {
|
|
747
|
+
async getById(id) {
|
|
748
|
+
try {
|
|
749
|
+
const params = new URLSearchParams({ query: `id:"${id}"`, limit: "1" });
|
|
750
|
+
const body = await fetchProducts(params);
|
|
751
|
+
return body.data.length > 0 ? mapProduct(body.data[0], currencyCode) : null;
|
|
752
|
+
} catch {
|
|
753
|
+
return null;
|
|
754
|
+
}
|
|
755
|
+
},
|
|
756
|
+
async getByVariantId(variantId) {
|
|
757
|
+
try {
|
|
758
|
+
const params = new URLSearchParams({
|
|
759
|
+
query: `variants.id:"${variantId}"`,
|
|
760
|
+
limit: "1"
|
|
761
|
+
});
|
|
762
|
+
const body = await fetchProducts(params);
|
|
763
|
+
return body.data.length > 0 ? mapProduct(body.data[0], currencyCode) : null;
|
|
764
|
+
} catch {
|
|
765
|
+
return null;
|
|
766
|
+
}
|
|
767
|
+
},
|
|
768
|
+
async search(opts2) {
|
|
769
|
+
try {
|
|
770
|
+
const params = new URLSearchParams();
|
|
771
|
+
if (opts2 == null ? void 0 : opts2.query) {
|
|
772
|
+
params.set("query", `"${opts2.query.trim().replace(/"/g, '\\"')}"`);
|
|
773
|
+
}
|
|
774
|
+
if (opts2 == null ? void 0 : opts2.pagination) {
|
|
775
|
+
if ("after" in opts2.pagination)
|
|
776
|
+
params.set("after", opts2.pagination.after);
|
|
777
|
+
else if ("before" in opts2.pagination)
|
|
778
|
+
params.set("before", opts2.pagination.before);
|
|
779
|
+
}
|
|
780
|
+
const body = await fetchProducts(params);
|
|
781
|
+
return {
|
|
782
|
+
items: body.data.map((p2) => mapProduct(p2, currencyCode)),
|
|
783
|
+
pageInfo: {
|
|
784
|
+
hasNextPage: body.hasNextPage,
|
|
785
|
+
hasPrevPage: body.hasPrevPage,
|
|
786
|
+
startCursor: body.startCursor,
|
|
787
|
+
endCursor: body.endCursor
|
|
788
|
+
}
|
|
789
|
+
};
|
|
790
|
+
} catch {
|
|
791
|
+
return {
|
|
792
|
+
items: [],
|
|
793
|
+
pageInfo: {
|
|
794
|
+
hasNextPage: false,
|
|
795
|
+
hasPrevPage: false,
|
|
796
|
+
startCursor: null,
|
|
797
|
+
endCursor: null
|
|
798
|
+
}
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
};
|
|
803
|
+
}
|
|
681
804
|
const ProductServiceContext = createContext("services/product");
|
|
682
805
|
function createProductService(adapter) {
|
|
683
806
|
return {
|
|
@@ -759,14 +882,6 @@ function createMockSubscriptionAdapter() {
|
|
|
759
882
|
imageUrl: "https://images.unsplash.com/photo-1556228578-8c89e6adf883?w=200",
|
|
760
883
|
price: { amount: "24.00", currencyCode: "USD" },
|
|
761
884
|
description: "Lightweight daily sun protection"
|
|
762
|
-
},
|
|
763
|
-
{
|
|
764
|
-
id: "upsell-3",
|
|
765
|
-
variantId: "upsell-v-3",
|
|
766
|
-
title: "Collagen Eye Patches",
|
|
767
|
-
imageUrl: "https://images.unsplash.com/photo-1512290923902-8a9f81dc236c?w=200",
|
|
768
|
-
price: { amount: "18.00", currencyCode: "USD" },
|
|
769
|
-
description: "Depuffing under-eye treatment"
|
|
770
885
|
}
|
|
771
886
|
];
|
|
772
887
|
return {
|
|
@@ -777,7 +892,7 @@ function createMockSubscriptionAdapter() {
|
|
|
777
892
|
},
|
|
778
893
|
async search(options = {}) {
|
|
779
894
|
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
780
|
-
const pageSize =
|
|
895
|
+
const pageSize = 2;
|
|
781
896
|
const allItems = mockSubscriptions;
|
|
782
897
|
let startIndex = 0;
|
|
783
898
|
let endIndex = pageSize;
|
|
@@ -793,20 +908,22 @@ function createMockSubscriptionAdapter() {
|
|
|
793
908
|
}
|
|
794
909
|
}
|
|
795
910
|
const pageItems = allItems.slice(startIndex, endIndex);
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
items:
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
911
|
+
return {
|
|
912
|
+
_tag: "Success",
|
|
913
|
+
data: {
|
|
914
|
+
items: pageItems.map((sub) => ({
|
|
915
|
+
...sub,
|
|
916
|
+
items: sub.items.map((item) => ({ ...item })),
|
|
917
|
+
discounts: sub.discounts.map((discount) => ({ ...discount }))
|
|
918
|
+
})),
|
|
919
|
+
pageInfo: {
|
|
920
|
+
hasNextPage: endIndex < allItems.length,
|
|
921
|
+
hasPrevPage: startIndex > 0,
|
|
922
|
+
startCursor: pageItems.length > 0 ? startIndex.toString() : null,
|
|
923
|
+
endCursor: pageItems.length > 0 ? (endIndex - 1).toString() : null
|
|
924
|
+
}
|
|
807
925
|
}
|
|
808
926
|
};
|
|
809
|
-
return { _tag: "Success", data: paginatedList };
|
|
810
927
|
},
|
|
811
928
|
async addItem() {
|
|
812
929
|
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
@@ -830,26 +947,11 @@ function createMockSubscriptionAdapter() {
|
|
|
830
947
|
(sub) => sub.id === params.subscriptionId
|
|
831
948
|
);
|
|
832
949
|
if (!subscription) {
|
|
833
|
-
return {
|
|
834
|
-
_tag: "Failure",
|
|
835
|
-
error: "Subscription not found"
|
|
836
|
-
};
|
|
950
|
+
return { _tag: "Failure", error: "Subscription not found" };
|
|
837
951
|
}
|
|
838
952
|
subscription.nextDeliveryDate = new Date(params.newDate);
|
|
839
953
|
subscription.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
840
|
-
subscription
|
|
841
|
-
item.nextDeliveryDate = new Date(params.newDate);
|
|
842
|
-
});
|
|
843
|
-
return {
|
|
844
|
-
_tag: "Success",
|
|
845
|
-
data: {
|
|
846
|
-
...subscription,
|
|
847
|
-
items: subscription.items.map((item) => ({ ...item })),
|
|
848
|
-
discounts: subscription.discounts.map((discount) => ({
|
|
849
|
-
...discount
|
|
850
|
-
}))
|
|
851
|
-
}
|
|
852
|
-
};
|
|
954
|
+
return { _tag: "Success", data: { ...subscription } };
|
|
853
955
|
},
|
|
854
956
|
async resume(params) {
|
|
855
957
|
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
@@ -857,23 +959,11 @@ function createMockSubscriptionAdapter() {
|
|
|
857
959
|
(sub) => sub.id === params.subscriptionId
|
|
858
960
|
);
|
|
859
961
|
if (!subscription) {
|
|
860
|
-
return {
|
|
861
|
-
_tag: "Failure",
|
|
862
|
-
error: "Subscription not found"
|
|
863
|
-
};
|
|
962
|
+
return { _tag: "Failure", error: "Subscription not found" };
|
|
864
963
|
}
|
|
865
964
|
subscription.status = "active";
|
|
866
965
|
subscription.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
867
|
-
return {
|
|
868
|
-
_tag: "Success",
|
|
869
|
-
data: {
|
|
870
|
-
...subscription,
|
|
871
|
-
items: subscription.items.map((item) => ({ ...item })),
|
|
872
|
-
discounts: subscription.discounts.map((discount) => ({
|
|
873
|
-
...discount
|
|
874
|
-
}))
|
|
875
|
-
}
|
|
876
|
-
};
|
|
966
|
+
return { _tag: "Success", data: { ...subscription } };
|
|
877
967
|
},
|
|
878
968
|
async pause(params) {
|
|
879
969
|
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
@@ -881,23 +971,11 @@ function createMockSubscriptionAdapter() {
|
|
|
881
971
|
(sub) => sub.id === params.subscriptionId
|
|
882
972
|
);
|
|
883
973
|
if (!subscription) {
|
|
884
|
-
return {
|
|
885
|
-
_tag: "Failure",
|
|
886
|
-
error: "Subscription not found"
|
|
887
|
-
};
|
|
974
|
+
return { _tag: "Failure", error: "Subscription not found" };
|
|
888
975
|
}
|
|
889
976
|
subscription.status = "paused";
|
|
890
977
|
subscription.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
891
|
-
return {
|
|
892
|
-
_tag: "Success",
|
|
893
|
-
data: {
|
|
894
|
-
...subscription,
|
|
895
|
-
items: subscription.items.map((item) => ({ ...item })),
|
|
896
|
-
discounts: subscription.discounts.map((discount) => ({
|
|
897
|
-
...discount
|
|
898
|
-
}))
|
|
899
|
-
}
|
|
900
|
-
};
|
|
978
|
+
return { _tag: "Success", data: { ...subscription } };
|
|
901
979
|
},
|
|
902
980
|
async reactivate(params) {
|
|
903
981
|
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
@@ -905,23 +983,11 @@ function createMockSubscriptionAdapter() {
|
|
|
905
983
|
(sub) => sub.id === params.subscriptionId
|
|
906
984
|
);
|
|
907
985
|
if (!subscription) {
|
|
908
|
-
return {
|
|
909
|
-
_tag: "Failure",
|
|
910
|
-
error: "Subscription not found"
|
|
911
|
-
};
|
|
986
|
+
return { _tag: "Failure", error: "Subscription not found" };
|
|
912
987
|
}
|
|
913
988
|
subscription.status = "active";
|
|
914
989
|
subscription.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
915
|
-
return {
|
|
916
|
-
_tag: "Success",
|
|
917
|
-
data: {
|
|
918
|
-
...subscription,
|
|
919
|
-
items: subscription.items.map((item) => ({ ...item })),
|
|
920
|
-
discounts: subscription.discounts.map((discount) => ({
|
|
921
|
-
...discount
|
|
922
|
-
}))
|
|
923
|
-
}
|
|
924
|
-
};
|
|
990
|
+
return { _tag: "Success", data: { ...subscription } };
|
|
925
991
|
},
|
|
926
992
|
async cancel(params) {
|
|
927
993
|
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
@@ -929,23 +995,11 @@ function createMockSubscriptionAdapter() {
|
|
|
929
995
|
(sub) => sub.id === params.subscriptionId
|
|
930
996
|
);
|
|
931
997
|
if (!subscription) {
|
|
932
|
-
return {
|
|
933
|
-
_tag: "Failure",
|
|
934
|
-
error: "Subscription not found"
|
|
935
|
-
};
|
|
998
|
+
return { _tag: "Failure", error: "Subscription not found" };
|
|
936
999
|
}
|
|
937
1000
|
subscription.status = "canceled";
|
|
938
1001
|
subscription.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
939
|
-
return {
|
|
940
|
-
_tag: "Success",
|
|
941
|
-
data: {
|
|
942
|
-
...subscription,
|
|
943
|
-
items: subscription.items.map((item) => ({ ...item })),
|
|
944
|
-
discounts: subscription.discounts.map((discount) => ({
|
|
945
|
-
...discount
|
|
946
|
-
}))
|
|
947
|
-
}
|
|
948
|
-
};
|
|
1002
|
+
return { _tag: "Success", data: { ...subscription } };
|
|
949
1003
|
},
|
|
950
1004
|
async getAvailablePlans() {
|
|
951
1005
|
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
@@ -978,26 +1032,6 @@ function createMockSubscriptionAdapter() {
|
|
|
978
1032
|
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
979
1033
|
return { _tag: "Success", data: ((_a = mockSubscriptions[0]) == null ? void 0 : _a.id) ?? null };
|
|
980
1034
|
},
|
|
981
|
-
async getDeliveryFrequencies() {
|
|
982
|
-
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
983
|
-
return {
|
|
984
|
-
_tag: "Success",
|
|
985
|
-
data: [
|
|
986
|
-
{
|
|
987
|
-
id: "plan_1",
|
|
988
|
-
name: "Monthly",
|
|
989
|
-
billingPolicy: { intervalCount: 1, interval: "MONTH" },
|
|
990
|
-
deliveryPolicy: { intervalCount: 1, interval: "MONTH" }
|
|
991
|
-
},
|
|
992
|
-
{
|
|
993
|
-
id: "plan_2",
|
|
994
|
-
name: "Every 2 months",
|
|
995
|
-
billingPolicy: { intervalCount: 2, interval: "MONTH" },
|
|
996
|
-
deliveryPolicy: { intervalCount: 2, interval: "MONTH" }
|
|
997
|
-
}
|
|
998
|
-
]
|
|
999
|
-
};
|
|
1000
|
-
},
|
|
1001
1035
|
async getUpsellProducts() {
|
|
1002
1036
|
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
1003
1037
|
return { _tag: "Success", data: [...mockUpsellProducts] };
|
|
@@ -1005,74 +1039,96 @@ function createMockSubscriptionAdapter() {
|
|
|
1005
1039
|
async addUpsellProduct() {
|
|
1006
1040
|
await new Promise((resolve) => setTimeout(resolve, 400));
|
|
1007
1041
|
return { _tag: "Success", data: void 0 };
|
|
1008
|
-
},
|
|
1009
|
-
async changeFrequency(params) {
|
|
1010
|
-
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
1011
|
-
const subscription = mockSubscriptions.find(
|
|
1012
|
-
(sub) => sub.id === params.subscriptionId
|
|
1013
|
-
);
|
|
1014
|
-
if (!subscription) {
|
|
1015
|
-
return { _tag: "Failure", error: "Subscription not found" };
|
|
1016
|
-
}
|
|
1017
|
-
subscription.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1018
|
-
return {
|
|
1019
|
-
_tag: "Success",
|
|
1020
|
-
data: { ...subscription }
|
|
1021
|
-
};
|
|
1022
1042
|
}
|
|
1023
1043
|
};
|
|
1024
1044
|
}
|
|
1045
|
+
function mapSubscription(raw) {
|
|
1046
|
+
var _a, _b;
|
|
1047
|
+
const status = raw.status === "merged" ? "canceled" : raw.status;
|
|
1048
|
+
const deliveryPolicy = raw.deliveryPolicy ?? ((_b = (_a = raw.items) == null ? void 0 : _a[0]) == null ? void 0 : _b.deliveryPolicy);
|
|
1049
|
+
const frequency = deliveryPolicy ? `${deliveryPolicy.intervalCount} ${deliveryPolicy.interval}` : "";
|
|
1050
|
+
return {
|
|
1051
|
+
id: raw.id,
|
|
1052
|
+
customerId: "",
|
|
1053
|
+
items: (raw.items ?? []).map(
|
|
1054
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1055
|
+
(item) => ({
|
|
1056
|
+
id: item.id,
|
|
1057
|
+
productId: item.productId ?? item.product ?? "",
|
|
1058
|
+
variantId: item.variantId ?? item.variant ?? "",
|
|
1059
|
+
quantity: item.quantity,
|
|
1060
|
+
price: item.price ?? {
|
|
1061
|
+
amount: String(item.totalPrice ?? 0),
|
|
1062
|
+
currencyCode: raw.currencyCode ?? ""
|
|
1063
|
+
},
|
|
1064
|
+
nextDeliveryDate: item.nextDeliveryDate ? new Date(item.nextDeliveryDate) : null
|
|
1065
|
+
})
|
|
1066
|
+
),
|
|
1067
|
+
discounts: (raw.discounts ?? []).map(
|
|
1068
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1069
|
+
(d2) => {
|
|
1070
|
+
var _a2, _b2, _c;
|
|
1071
|
+
return {
|
|
1072
|
+
id: d2.id,
|
|
1073
|
+
type: ((_a2 = d2.value) == null ? void 0 : _a2.type) === "fixed-amount" || d2.type === "fixed_amount" ? "fixed_amount" : "percentage",
|
|
1074
|
+
value: ((_b2 = d2.value) == null ? void 0 : _b2.amount) ?? ((_c = d2.value) == null ? void 0 : _c.percentage) ?? d2.value ?? 0,
|
|
1075
|
+
code: d2.title ?? d2.code ?? "",
|
|
1076
|
+
description: d2.description ?? ""
|
|
1077
|
+
};
|
|
1078
|
+
}
|
|
1079
|
+
),
|
|
1080
|
+
status,
|
|
1081
|
+
nextDeliveryDate: raw.nextBillingDate ? new Date(raw.nextBillingDate) : raw.nextDeliveryDate ? new Date(raw.nextDeliveryDate) : null,
|
|
1082
|
+
frequency,
|
|
1083
|
+
createdAt: raw.createdAt,
|
|
1084
|
+
updatedAt: raw.updatedAt
|
|
1085
|
+
};
|
|
1086
|
+
}
|
|
1025
1087
|
function createApiSubscriptionAdapter(fetcher) {
|
|
1026
1088
|
return {
|
|
1027
1089
|
async search(options) {
|
|
1090
|
+
var _a;
|
|
1028
1091
|
try {
|
|
1029
1092
|
const params = new URLSearchParams();
|
|
1030
|
-
if (options == null ? void 0 : options.filters) {
|
|
1031
|
-
|
|
1093
|
+
if ((_a = options == null ? void 0 : options.filters) == null ? void 0 : _a.length) {
|
|
1094
|
+
const q2 = options.filters.filter((f2) => Object.keys(f2).length > 0).flatMap((f2) => Object.entries(f2).filter(([, v2]) => Boolean(v2))).map(([k2, v2]) => `${k2}:'${v2}'`).join(" AND ");
|
|
1095
|
+
if (q2) params.set("query", q2);
|
|
1032
1096
|
}
|
|
1033
1097
|
if (options == null ? void 0 : options.pagination) {
|
|
1034
|
-
if ("after" in options.pagination)
|
|
1098
|
+
if ("after" in options.pagination)
|
|
1035
1099
|
params.set("after", options.pagination.after);
|
|
1036
|
-
|
|
1100
|
+
else if ("before" in options.pagination)
|
|
1037
1101
|
params.set("before", options.pagination.before);
|
|
1038
|
-
}
|
|
1039
1102
|
}
|
|
1040
1103
|
const query = params.toString() ? `?${params.toString()}` : "";
|
|
1041
1104
|
const res = await fetcher(`/customer/v1/subscriptions${query}`);
|
|
1042
1105
|
if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
|
|
1043
1106
|
const body = await res.json();
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1107
|
+
return {
|
|
1108
|
+
_tag: "Success",
|
|
1109
|
+
data: {
|
|
1110
|
+
items: body.data.map(mapSubscription),
|
|
1111
|
+
pageInfo: {
|
|
1112
|
+
hasNextPage: body.hasNextPage,
|
|
1113
|
+
hasPrevPage: body.hasPrevPage,
|
|
1114
|
+
startCursor: body.startCursor,
|
|
1115
|
+
endCursor: body.endCursor
|
|
1051
1116
|
}
|
|
1052
|
-
});
|
|
1053
|
-
});
|
|
1054
|
-
const data = {
|
|
1055
|
-
items: body.data,
|
|
1056
|
-
pageInfo: {
|
|
1057
|
-
hasNextPage: body.hasNextPage,
|
|
1058
|
-
hasPrevPage: body.hasPrevPage,
|
|
1059
|
-
startCursor: body.startCursor,
|
|
1060
|
-
endCursor: body.endCursor
|
|
1061
1117
|
}
|
|
1062
1118
|
};
|
|
1063
|
-
return { _tag: "Success", data };
|
|
1064
1119
|
} catch (e2) {
|
|
1065
1120
|
return { _tag: "Failure", error: e2 };
|
|
1066
1121
|
}
|
|
1067
1122
|
},
|
|
1068
1123
|
async getById(id) {
|
|
1069
1124
|
try {
|
|
1070
|
-
const res = await fetcher(
|
|
1125
|
+
const res = await fetcher(
|
|
1126
|
+
`/customer/v1/subscriptions?query=id:"${id}"&limit=1`
|
|
1127
|
+
);
|
|
1071
1128
|
if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
|
|
1072
|
-
const
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
return { _tag: "Success", data };
|
|
1129
|
+
const body = await res.json();
|
|
1130
|
+
const raw = body.data[0];
|
|
1131
|
+
return { _tag: "Success", data: raw ? mapSubscription(raw) : null };
|
|
1076
1132
|
} catch (e2) {
|
|
1077
1133
|
return { _tag: "Failure", error: e2 };
|
|
1078
1134
|
}
|
|
@@ -1133,21 +1189,20 @@ function createApiSubscriptionAdapter(fetcher) {
|
|
|
1133
1189
|
return { _tag: "Failure", error: e2 };
|
|
1134
1190
|
}
|
|
1135
1191
|
},
|
|
1192
|
+
// Uses PATCH /customer/v1/subscriptions/{id} — the dedicated /reschedule route does not exist.
|
|
1136
1193
|
async reschedule({ subscriptionId, newDate }) {
|
|
1137
1194
|
try {
|
|
1138
1195
|
const res = await fetcher(
|
|
1139
|
-
`/customer/v1/subscriptions/${subscriptionId}
|
|
1196
|
+
`/customer/v1/subscriptions/${subscriptionId}`,
|
|
1140
1197
|
{
|
|
1141
|
-
method: "
|
|
1198
|
+
method: "PATCH",
|
|
1142
1199
|
headers: { "Content-Type": "application/json" },
|
|
1143
|
-
body: JSON.stringify({ newDate })
|
|
1200
|
+
body: JSON.stringify({ nextBillingDate: newDate })
|
|
1144
1201
|
}
|
|
1145
1202
|
);
|
|
1146
1203
|
if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
|
|
1147
1204
|
const data = await res.json();
|
|
1148
|
-
|
|
1149
|
-
data.nextDeliveryDate = new Date(data.nextDeliveryDate);
|
|
1150
|
-
return { _tag: "Success", data };
|
|
1205
|
+
return { _tag: "Success", data: mapSubscription(data) };
|
|
1151
1206
|
} catch (e2) {
|
|
1152
1207
|
return { _tag: "Failure", error: e2 };
|
|
1153
1208
|
}
|
|
@@ -1160,7 +1215,7 @@ function createApiSubscriptionAdapter(fetcher) {
|
|
|
1160
1215
|
);
|
|
1161
1216
|
if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
|
|
1162
1217
|
const data = await res.json();
|
|
1163
|
-
return { _tag: "Success", data };
|
|
1218
|
+
return { _tag: "Success", data: mapSubscription(data) };
|
|
1164
1219
|
} catch (e2) {
|
|
1165
1220
|
return { _tag: "Failure", error: e2 };
|
|
1166
1221
|
}
|
|
@@ -1173,7 +1228,7 @@ function createApiSubscriptionAdapter(fetcher) {
|
|
|
1173
1228
|
);
|
|
1174
1229
|
if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
|
|
1175
1230
|
const data = await res.json();
|
|
1176
|
-
return { _tag: "Success", data };
|
|
1231
|
+
return { _tag: "Success", data: mapSubscription(data) };
|
|
1177
1232
|
} catch (e2) {
|
|
1178
1233
|
return { _tag: "Failure", error: e2 };
|
|
1179
1234
|
}
|
|
@@ -1186,7 +1241,7 @@ function createApiSubscriptionAdapter(fetcher) {
|
|
|
1186
1241
|
);
|
|
1187
1242
|
if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
|
|
1188
1243
|
const data = await res.json();
|
|
1189
|
-
return { _tag: "Success", data };
|
|
1244
|
+
return { _tag: "Success", data: mapSubscription(data) };
|
|
1190
1245
|
} catch (e2) {
|
|
1191
1246
|
return { _tag: "Failure", error: e2 };
|
|
1192
1247
|
}
|
|
@@ -1198,71 +1253,81 @@ function createApiSubscriptionAdapter(fetcher) {
|
|
|
1198
1253
|
{
|
|
1199
1254
|
method: "POST",
|
|
1200
1255
|
headers: { "Content-Type": "application/json" },
|
|
1201
|
-
body: JSON.stringify({ reason })
|
|
1256
|
+
body: JSON.stringify({ cancellationReason: reason })
|
|
1202
1257
|
}
|
|
1203
1258
|
);
|
|
1204
1259
|
if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
|
|
1205
1260
|
const data = await res.json();
|
|
1206
|
-
return { _tag: "Success", data };
|
|
1261
|
+
return { _tag: "Success", data: mapSubscription(data) };
|
|
1207
1262
|
} catch (e2) {
|
|
1208
1263
|
return { _tag: "Failure", error: e2 };
|
|
1209
1264
|
}
|
|
1210
1265
|
},
|
|
1266
|
+
// Legacy endpoint — no /customer/v1/subscriptions/{id}/plans exists yet.
|
|
1211
1267
|
async getAvailablePlans({ subscriptionId }) {
|
|
1212
1268
|
try {
|
|
1213
1269
|
const res = await fetcher(
|
|
1214
|
-
`/customer/
|
|
1270
|
+
`/customer/subscriptions/${subscriptionId}/plans`
|
|
1215
1271
|
);
|
|
1216
1272
|
if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
|
|
1217
1273
|
const data = await res.json();
|
|
1218
|
-
return { _tag: "Success", data
|
|
1274
|
+
return { _tag: "Success", data };
|
|
1219
1275
|
} catch (e2) {
|
|
1220
1276
|
return { _tag: "Failure", error: e2 };
|
|
1221
1277
|
}
|
|
1222
1278
|
},
|
|
1279
|
+
// Legacy endpoint — no /customer/v1 equivalent exists yet.
|
|
1223
1280
|
async getDefaultSubscriptionId() {
|
|
1224
|
-
var _a;
|
|
1225
|
-
try {
|
|
1226
|
-
const res = await fetcher(`/customer/v1/subscriptions?limit=1`);
|
|
1227
|
-
if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
|
|
1228
|
-
const body = await res.json();
|
|
1229
|
-
return { _tag: "Success", data: ((_a = body.data[0]) == null ? void 0 : _a.id) ?? null };
|
|
1230
|
-
} catch (e2) {
|
|
1231
|
-
return { _tag: "Failure", error: e2 };
|
|
1232
|
-
}
|
|
1233
|
-
},
|
|
1234
|
-
async getDeliveryFrequencies({ subscriptionId }) {
|
|
1235
1281
|
try {
|
|
1236
1282
|
const res = await fetcher(
|
|
1237
|
-
`/customer/
|
|
1283
|
+
`/customer/subscriptions/one-by-next-billing-date`
|
|
1238
1284
|
);
|
|
1239
1285
|
if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
|
|
1240
1286
|
const data = await res.json();
|
|
1241
|
-
return { _tag: "Success", data: data.
|
|
1287
|
+
return { _tag: "Success", data: (data == null ? void 0 : data.id) ?? null };
|
|
1242
1288
|
} catch (e2) {
|
|
1243
1289
|
return { _tag: "Failure", error: e2 };
|
|
1244
1290
|
}
|
|
1245
1291
|
},
|
|
1292
|
+
// Legacy endpoint — no /customer/v1/subscriptions/{id}/upsells exists yet.
|
|
1246
1293
|
async getUpsellProducts({ subscriptionId }) {
|
|
1247
1294
|
try {
|
|
1248
1295
|
const res = await fetcher(
|
|
1249
|
-
`/customer/
|
|
1296
|
+
`/customer/subscriptions/${subscriptionId}/upsell-products`
|
|
1250
1297
|
);
|
|
1251
1298
|
if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
|
|
1252
1299
|
const data = await res.json();
|
|
1253
|
-
|
|
1300
|
+
const products = data.map((p2) => {
|
|
1301
|
+
var _a, _b, _c, _d, _e;
|
|
1302
|
+
return {
|
|
1303
|
+
id: p2.id,
|
|
1304
|
+
variantId: ((_b = (_a = p2.variants) == null ? void 0 : _a[0]) == null ? void 0 : _b.id) ?? "",
|
|
1305
|
+
title: p2.title ?? "",
|
|
1306
|
+
imageUrl: ((_c = p2.featuredImage) == null ? void 0 : _c.url) ?? void 0,
|
|
1307
|
+
price: {
|
|
1308
|
+
amount: String(((_e = (_d = p2.variants) == null ? void 0 : _d[0]) == null ? void 0 : _e.price) ?? 0),
|
|
1309
|
+
currencyCode: p2.currencyCode ?? ""
|
|
1310
|
+
}
|
|
1311
|
+
};
|
|
1312
|
+
});
|
|
1313
|
+
return { _tag: "Success", data: products };
|
|
1254
1314
|
} catch (e2) {
|
|
1255
1315
|
return { _tag: "Failure", error: e2 };
|
|
1256
1316
|
}
|
|
1257
1317
|
},
|
|
1318
|
+
// Legacy endpoint — no /customer/v1/subscriptions/{id}/upsells POST exists yet.
|
|
1258
1319
|
async addUpsellProduct({ subscriptionId, variantId, quantity, oneTime }) {
|
|
1259
1320
|
try {
|
|
1260
1321
|
const res = await fetcher(
|
|
1261
|
-
`/customer/
|
|
1322
|
+
`/customer/subscriptions/${subscriptionId}/upsell`,
|
|
1262
1323
|
{
|
|
1263
1324
|
method: "POST",
|
|
1264
1325
|
headers: { "Content-Type": "application/json" },
|
|
1265
|
-
body: JSON.stringify({
|
|
1326
|
+
body: JSON.stringify({
|
|
1327
|
+
productVariantId: variantId,
|
|
1328
|
+
quantity,
|
|
1329
|
+
...oneTime ? { renewalLimit: 1 } : {}
|
|
1330
|
+
})
|
|
1266
1331
|
}
|
|
1267
1332
|
);
|
|
1268
1333
|
if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
|
|
@@ -1270,23 +1335,6 @@ function createApiSubscriptionAdapter(fetcher) {
|
|
|
1270
1335
|
} catch (e2) {
|
|
1271
1336
|
return { _tag: "Failure", error: e2 };
|
|
1272
1337
|
}
|
|
1273
|
-
},
|
|
1274
|
-
async changeFrequency({ subscriptionId, sellingPlanId }) {
|
|
1275
|
-
try {
|
|
1276
|
-
const res = await fetcher(
|
|
1277
|
-
`/customer/v1/subscriptions/${subscriptionId}/frequency`,
|
|
1278
|
-
{
|
|
1279
|
-
method: "POST",
|
|
1280
|
-
headers: { "Content-Type": "application/json" },
|
|
1281
|
-
body: JSON.stringify({ sellingPlanId })
|
|
1282
|
-
}
|
|
1283
|
-
);
|
|
1284
|
-
if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
|
|
1285
|
-
const data = await res.json();
|
|
1286
|
-
return { _tag: "Success", data };
|
|
1287
|
-
} catch (e2) {
|
|
1288
|
-
return { _tag: "Failure", error: e2 };
|
|
1289
|
-
}
|
|
1290
1338
|
}
|
|
1291
1339
|
};
|
|
1292
1340
|
}
|
|
@@ -1342,27 +1390,68 @@ function createSubscriptionService(adapter) {
|
|
|
1342
1390
|
cancel: (subscriptionId, reason) => adapter.cancel({ subscriptionId, reason }),
|
|
1343
1391
|
getAvailablePlans: (subscriptionId) => adapter.getAvailablePlans({ subscriptionId }),
|
|
1344
1392
|
getDefaultSubscriptionId: () => adapter.getDefaultSubscriptionId(),
|
|
1345
|
-
getDeliveryFrequencies: (params) => adapter.getDeliveryFrequencies ? adapter.getDeliveryFrequencies(params) : Promise.resolve({ _tag: "Success", data: [] }),
|
|
1346
1393
|
getUpsellProducts: (params) => adapter.getUpsellProducts ? adapter.getUpsellProducts(params) : Promise.resolve({ _tag: "Success", data: [] }),
|
|
1347
|
-
addUpsellProduct: (params) => adapter.addUpsellProduct ? adapter.addUpsellProduct(params) : Promise.resolve({ _tag: "Success", data: void 0 })
|
|
1348
|
-
changeFrequency: (params) => adapter.changeFrequency ? adapter.changeFrequency(params) : Promise.resolve({ _tag: "Failure", error: "Not implemented" })
|
|
1394
|
+
addUpsellProduct: (params) => adapter.addUpsellProduct ? adapter.addUpsellProduct(params) : Promise.resolve({ _tag: "Success", data: void 0 })
|
|
1349
1395
|
};
|
|
1350
1396
|
}
|
|
1351
1397
|
const CustomerServiceContext = createContext("services/customer");
|
|
1352
|
-
function createCustomerService() {
|
|
1398
|
+
function createCustomerService(adapter) {
|
|
1353
1399
|
const current = d(null);
|
|
1354
|
-
|
|
1355
|
-
|
|
1400
|
+
return {
|
|
1401
|
+
current,
|
|
1402
|
+
async getCurrent() {
|
|
1403
|
+
const result = await adapter.getCurrent();
|
|
1404
|
+
if (result._tag === "Success") current.value = result.data;
|
|
1405
|
+
return result;
|
|
1406
|
+
}
|
|
1407
|
+
};
|
|
1408
|
+
}
|
|
1409
|
+
function createMockCustomerAdapter() {
|
|
1410
|
+
const customer = { id: "customer-1", name: "Customer 1" };
|
|
1411
|
+
return {
|
|
1412
|
+
async getCurrent() {
|
|
1413
|
+
return { _tag: "Success", data: customer };
|
|
1414
|
+
}
|
|
1415
|
+
};
|
|
1416
|
+
}
|
|
1417
|
+
function createApiCustomerAdapter(fetcher) {
|
|
1418
|
+
return {
|
|
1419
|
+
async getCurrent() {
|
|
1420
|
+
try {
|
|
1421
|
+
const res = await fetcher("/customer/info");
|
|
1422
|
+
if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
|
|
1423
|
+
const data = await res.json();
|
|
1424
|
+
const name = [data.firstName, data.lastName].filter(Boolean).join(" ") || data.email || "";
|
|
1425
|
+
return {
|
|
1426
|
+
_tag: "Success",
|
|
1427
|
+
data: { id: data.id, name, email: data.email }
|
|
1428
|
+
};
|
|
1429
|
+
} catch (e2) {
|
|
1430
|
+
return { _tag: "Failure", error: e2 };
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
};
|
|
1434
|
+
}
|
|
1435
|
+
function mapOrder(order) {
|
|
1436
|
+
const items = order.items.map((item) => ({
|
|
1437
|
+
id: item.id,
|
|
1438
|
+
productId: item.productId ?? "",
|
|
1439
|
+
variantId: item.variantId ?? "",
|
|
1440
|
+
quantity: item.quantity
|
|
1441
|
+
}));
|
|
1442
|
+
return {
|
|
1443
|
+
id: order.id,
|
|
1444
|
+
customerId: "",
|
|
1445
|
+
items,
|
|
1446
|
+
deliveryDate: order.placedAt ?? null,
|
|
1447
|
+
status: "delivered"
|
|
1448
|
+
};
|
|
1356
1449
|
}
|
|
1357
1450
|
function createMockOrderAdapter() {
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
items: [],
|
|
1363
|
-
deliveryDate: new Date(Date.now() + 7 * 24 * 60 * 60 * 1e3).toISOString().split("T")[0] ?? null,
|
|
1364
|
-
status: "pending"
|
|
1365
|
-
},
|
|
1451
|
+
const now = Date.now();
|
|
1452
|
+
const past1 = new Date(now - 30 * 24 * 60 * 60 * 1e3).toISOString().split("T")[0] ?? null;
|
|
1453
|
+
const past2 = new Date(now - 60 * 24 * 60 * 60 * 1e3).toISOString().split("T")[0] ?? null;
|
|
1454
|
+
const orders = [
|
|
1366
1455
|
{
|
|
1367
1456
|
id: "order-2",
|
|
1368
1457
|
customerId: "customer-1",
|
|
@@ -1370,121 +1459,47 @@ function createMockOrderAdapter() {
|
|
|
1370
1459
|
{ id: "item-1", productId: "p1", variantId: "v1", quantity: 1 },
|
|
1371
1460
|
{ id: "item-2", productId: "p2", variantId: "v2", quantity: 2 }
|
|
1372
1461
|
],
|
|
1373
|
-
deliveryDate:
|
|
1462
|
+
deliveryDate: past1,
|
|
1374
1463
|
status: "delivered"
|
|
1375
1464
|
},
|
|
1376
1465
|
{
|
|
1377
1466
|
id: "order-3",
|
|
1378
1467
|
customerId: "customer-1",
|
|
1379
|
-
items: [
|
|
1380
|
-
|
|
1381
|
-
],
|
|
1382
|
-
deliveryDate: new Date(Date.now() - 60 * 24 * 60 * 60 * 1e3).toISOString().split("T")[0] ?? null,
|
|
1468
|
+
items: [{ id: "item-3", productId: "p1", variantId: "v1", quantity: 1 }],
|
|
1469
|
+
deliveryDate: past2,
|
|
1383
1470
|
status: "delivered"
|
|
1384
|
-
},
|
|
1385
|
-
{
|
|
1386
|
-
id: "order-4",
|
|
1387
|
-
customerId: "customer-1",
|
|
1388
|
-
items: [],
|
|
1389
|
-
deliveryDate: new Date(Date.now() - 90 * 24 * 60 * 60 * 1e3).toISOString().split("T")[0] ?? null,
|
|
1390
|
-
status: "skipped"
|
|
1391
1471
|
}
|
|
1392
1472
|
];
|
|
1393
1473
|
return {
|
|
1394
|
-
async getUpcoming() {
|
|
1395
|
-
return {
|
|
1396
|
-
_tag: "Success",
|
|
1397
|
-
data: orders.filter((o2) => o2.status === "pending")
|
|
1398
|
-
};
|
|
1399
|
-
},
|
|
1400
1474
|
async getHistory() {
|
|
1401
|
-
return {
|
|
1402
|
-
_tag: "Success",
|
|
1403
|
-
data: orders.filter((o2) => o2.status === "delivered" || o2.status === "skipped").sort((a3, b3) => (b3.deliveryDate ?? "").localeCompare(a3.deliveryDate ?? ""))
|
|
1404
|
-
};
|
|
1475
|
+
return { _tag: "Success", data: orders };
|
|
1405
1476
|
},
|
|
1406
1477
|
async getById(id) {
|
|
1407
|
-
return {
|
|
1408
|
-
_tag: "Success",
|
|
1409
|
-
data: orders.find((o2) => o2.id === id) ?? null
|
|
1410
|
-
};
|
|
1411
|
-
},
|
|
1412
|
-
async updateItems(orderId, items) {
|
|
1413
|
-
const order = orders.find((o2) => o2.id === orderId);
|
|
1414
|
-
if (!order) return { _tag: "Failure", error: "Order not found" };
|
|
1415
|
-
const updated = {
|
|
1416
|
-
...order,
|
|
1417
|
-
items: items.map((item, i2) => ({
|
|
1418
|
-
id: `item-${Date.now()}-${i2}`,
|
|
1419
|
-
...item
|
|
1420
|
-
}))
|
|
1421
|
-
};
|
|
1422
|
-
orders = orders.map((o2) => o2.id === orderId ? updated : o2);
|
|
1423
|
-
return { _tag: "Success", data: updated };
|
|
1424
|
-
},
|
|
1425
|
-
async skip(orderId) {
|
|
1426
|
-
const order = orders.find((o2) => o2.id === orderId);
|
|
1427
|
-
if (!order) return { _tag: "Failure", error: "Order not found" };
|
|
1428
|
-
const updated = { ...order, status: "skipped" };
|
|
1429
|
-
orders = orders.map((o2) => o2.id === orderId ? updated : o2);
|
|
1430
|
-
return { _tag: "Success", data: updated };
|
|
1478
|
+
return { _tag: "Success", data: orders.find((o2) => o2.id === id) ?? null };
|
|
1431
1479
|
}
|
|
1432
1480
|
};
|
|
1433
1481
|
}
|
|
1434
1482
|
function createApiOrderAdapter(fetcher) {
|
|
1435
1483
|
return {
|
|
1436
|
-
async getUpcoming() {
|
|
1437
|
-
try {
|
|
1438
|
-
const res = await fetcher("/customer/v1/orders?status=pending");
|
|
1439
|
-
if (!res.ok) return { _tag: "Failure", error: await res.text() };
|
|
1440
|
-
const body = await res.json();
|
|
1441
|
-
return { _tag: "Success", data: body.orders };
|
|
1442
|
-
} catch (e2) {
|
|
1443
|
-
return { _tag: "Failure", error: e2 };
|
|
1444
|
-
}
|
|
1445
|
-
},
|
|
1446
1484
|
async getHistory() {
|
|
1447
1485
|
try {
|
|
1448
|
-
const res = await fetcher("/customer/v1/orders
|
|
1449
|
-
if (!res.ok) return { _tag: "Failure", error:
|
|
1486
|
+
const res = await fetcher("/customer/v1/orders");
|
|
1487
|
+
if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
|
|
1450
1488
|
const body = await res.json();
|
|
1451
|
-
return { _tag: "Success", data: body.orders };
|
|
1489
|
+
return { _tag: "Success", data: body.orders.map(mapOrder) };
|
|
1452
1490
|
} catch (e2) {
|
|
1453
1491
|
return { _tag: "Failure", error: e2 };
|
|
1454
1492
|
}
|
|
1455
1493
|
},
|
|
1456
1494
|
async getById(id) {
|
|
1457
1495
|
try {
|
|
1458
|
-
const res = await fetcher(
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
return { _tag: "
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
},
|
|
1466
|
-
async updateItems(orderId, items) {
|
|
1467
|
-
try {
|
|
1468
|
-
const res = await fetcher(`/customer/v1/orders/${orderId}/items`, {
|
|
1469
|
-
method: "PUT",
|
|
1470
|
-
headers: { "Content-Type": "application/json" },
|
|
1471
|
-
body: JSON.stringify({ items })
|
|
1472
|
-
});
|
|
1473
|
-
if (!res.ok) return { _tag: "Failure", error: await res.text() };
|
|
1474
|
-
const data = await res.json();
|
|
1475
|
-
return { _tag: "Success", data };
|
|
1476
|
-
} catch (e2) {
|
|
1477
|
-
return { _tag: "Failure", error: e2 };
|
|
1478
|
-
}
|
|
1479
|
-
},
|
|
1480
|
-
async skip(orderId) {
|
|
1481
|
-
try {
|
|
1482
|
-
const res = await fetcher(`/customer/v1/orders/${orderId}/skip`, {
|
|
1483
|
-
method: "POST"
|
|
1484
|
-
});
|
|
1485
|
-
if (!res.ok) return { _tag: "Failure", error: await res.text() };
|
|
1486
|
-
const data = await res.json();
|
|
1487
|
-
return { _tag: "Success", data };
|
|
1496
|
+
const res = await fetcher(
|
|
1497
|
+
`/customer/v1/orders?query=id:"${id}"&limit=1`
|
|
1498
|
+
);
|
|
1499
|
+
if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
|
|
1500
|
+
const body = await res.json();
|
|
1501
|
+
const raw = body.orders[0];
|
|
1502
|
+
return { _tag: "Success", data: raw ? mapOrder(raw) : null };
|
|
1488
1503
|
} catch (e2) {
|
|
1489
1504
|
return { _tag: "Failure", error: e2 };
|
|
1490
1505
|
}
|
|
@@ -1494,11 +1509,8 @@ function createApiOrderAdapter(fetcher) {
|
|
|
1494
1509
|
const OrderServiceContext = createContext("services/order");
|
|
1495
1510
|
function createOrderService(adapter) {
|
|
1496
1511
|
return {
|
|
1497
|
-
getUpcoming: () => adapter.getUpcoming(),
|
|
1498
1512
|
getHistory: () => adapter.getHistory(),
|
|
1499
|
-
getById: (id) => adapter.getById(id)
|
|
1500
|
-
updateItems: (orderId, items) => adapter.updateItems(orderId, items),
|
|
1501
|
-
skip: (orderId) => adapter.skip(orderId)
|
|
1513
|
+
getById: (id) => adapter.getById(id)
|
|
1502
1514
|
};
|
|
1503
1515
|
}
|
|
1504
1516
|
function futureDateStr(daysFromNow) {
|
|
@@ -1613,9 +1625,7 @@ function createApiSchedulesAdapter(fetcher) {
|
|
|
1613
1625
|
return {
|
|
1614
1626
|
async getUpcomingOrders(count) {
|
|
1615
1627
|
try {
|
|
1616
|
-
const res = await fetcher(
|
|
1617
|
-
`/customer/v1/schedules?count=${count}`
|
|
1618
|
-
);
|
|
1628
|
+
const res = await fetcher(`/customer/v1/schedules/?count=${count}`);
|
|
1619
1629
|
if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
|
|
1620
1630
|
const data = await res.json();
|
|
1621
1631
|
return { _tag: "Success", data: data.orders };
|
|
@@ -1628,17 +1638,30 @@ function createApiSchedulesAdapter(fetcher) {
|
|
|
1628
1638
|
const res = await fetcher(`/customer/v1/schedules/adjustments`);
|
|
1629
1639
|
if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
|
|
1630
1640
|
const data = await res.json();
|
|
1631
|
-
|
|
1641
|
+
const adjustments = data.data.map((a3) => ({
|
|
1642
|
+
id: a3.id,
|
|
1643
|
+
subscriptionId: a3.subscriptionId ?? "",
|
|
1644
|
+
type: a3.type === "CHANGE_DATE" ? "date_change" : "skip",
|
|
1645
|
+
newDate: a3.newDate
|
|
1646
|
+
}));
|
|
1647
|
+
return { _tag: "Success", data: adjustments };
|
|
1632
1648
|
} catch (e2) {
|
|
1633
1649
|
return { _tag: "Failure", error: e2 };
|
|
1634
1650
|
}
|
|
1635
1651
|
},
|
|
1636
|
-
async skipOrder(
|
|
1652
|
+
async skipOrder({ cycle, date }) {
|
|
1653
|
+
if (cycle == null && date == null) {
|
|
1654
|
+
return { _tag: "Failure", error: "Either cycle or date is required for skipOrder" };
|
|
1655
|
+
}
|
|
1637
1656
|
try {
|
|
1657
|
+
const matcher = cycle != null ? { type: "CYCLE", input: { cycle } } : { type: "DATE", input: { date: new Date(date).toISOString() } };
|
|
1638
1658
|
const res = await fetcher(`/customer/v1/schedules/adjustments`, {
|
|
1639
1659
|
method: "POST",
|
|
1640
1660
|
headers: { "Content-Type": "application/json" },
|
|
1641
|
-
body: JSON.stringify({
|
|
1661
|
+
body: JSON.stringify({
|
|
1662
|
+
matcher,
|
|
1663
|
+
action: { type: "SKIP_ORDER", input: { reason: "" } }
|
|
1664
|
+
})
|
|
1642
1665
|
});
|
|
1643
1666
|
if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
|
|
1644
1667
|
return { _tag: "Success", data: void 0 };
|
|
@@ -1646,12 +1669,25 @@ function createApiSchedulesAdapter(fetcher) {
|
|
|
1646
1669
|
return { _tag: "Failure", error: e2 };
|
|
1647
1670
|
}
|
|
1648
1671
|
},
|
|
1649
|
-
async changeDateAdjustment(
|
|
1672
|
+
async changeDateAdjustment({ newDate, currentDate }) {
|
|
1673
|
+
if (currentDate == null) {
|
|
1674
|
+
return {
|
|
1675
|
+
_tag: "Failure",
|
|
1676
|
+
error: "currentDate is required for changeDateAdjustment"
|
|
1677
|
+
};
|
|
1678
|
+
}
|
|
1650
1679
|
try {
|
|
1680
|
+
const matcher = { type: "DATE", input: { date: new Date(currentDate).toISOString() } };
|
|
1651
1681
|
const res = await fetcher(`/customer/v1/schedules/adjustments`, {
|
|
1652
1682
|
method: "POST",
|
|
1653
1683
|
headers: { "Content-Type": "application/json" },
|
|
1654
|
-
body: JSON.stringify({
|
|
1684
|
+
body: JSON.stringify({
|
|
1685
|
+
matcher,
|
|
1686
|
+
action: {
|
|
1687
|
+
type: "CHANGE_DATE",
|
|
1688
|
+
input: { newDate: new Date(newDate).toISOString() }
|
|
1689
|
+
}
|
|
1690
|
+
})
|
|
1655
1691
|
});
|
|
1656
1692
|
if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
|
|
1657
1693
|
return { _tag: "Success", data: void 0 };
|
|
@@ -1993,7 +2029,10 @@ export {
|
|
|
1993
2029
|
T2 as TranslationContext,
|
|
1994
2030
|
W as WorkflowServiceContext,
|
|
1995
2031
|
w as computed,
|
|
2032
|
+
createApiCustomerAdapter,
|
|
2033
|
+
createApiLoginAdapter,
|
|
1996
2034
|
createApiOrderAdapter,
|
|
2035
|
+
createApiProductAdapter,
|
|
1997
2036
|
createApiSchedulesAdapter,
|
|
1998
2037
|
createApiSubscriptionAdapter,
|
|
1999
2038
|
a as createBlockInstance,
|
|
@@ -2002,6 +2041,9 @@ export {
|
|
|
2002
2041
|
f as createCeRenderer,
|
|
2003
2042
|
createContext,
|
|
2004
2043
|
createCustomerService,
|
|
2044
|
+
createLoginService,
|
|
2045
|
+
createMockCustomerAdapter,
|
|
2046
|
+
createMockLoginAdapter,
|
|
2005
2047
|
createMockOrderAdapter,
|
|
2006
2048
|
createMockProductAdapter,
|
|
2007
2049
|
createMockSchedulesAdapter,
|