@occluze/tether 0.6.7 → 0.7.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/README.md +11 -11
- package/dist/esm/astro.js +2 -2
- package/dist/esm/chunks/account-UIPWJQ3Y.js +1 -0
- package/dist/esm/chunks/account-pages-6ROA6Y4V.js +1 -0
- package/dist/esm/chunks/analytics-2V632IRV.js +1 -0
- package/dist/esm/chunks/chunk-4GCXM764.js +1 -0
- package/dist/esm/chunks/chunk-56FCLJJD.js +1 -0
- package/dist/esm/chunks/chunk-5Z5O3767.js +1 -0
- package/dist/esm/chunks/chunk-6OZJCAGZ.js +1 -0
- package/dist/esm/chunks/chunk-A5SYCVQM.js +1 -0
- package/dist/esm/chunks/chunk-BA4LQJJQ.js +1 -0
- package/dist/esm/chunks/chunk-BFTZR4OB.js +4 -0
- package/dist/esm/chunks/chunk-C5JYQCWH.js +1 -0
- package/dist/esm/chunks/chunk-E5YO6274.js +1 -0
- package/dist/esm/chunks/chunk-MPDWM2NN.js +1 -0
- package/dist/esm/chunks/chunk-T44MUL4Y.js +1 -0
- package/dist/esm/chunks/chunk-YLUULATY.js +1 -0
- package/dist/esm/chunks/diagnose-3FEKRIEK.js +14 -0
- package/dist/esm/chunks/extras-6POFBNOP.js +1 -0
- package/dist/esm/chunks/markets-ui-FD6NI2OG.js +1 -0
- package/dist/esm/chunks/search-UJ73YBQ5.js +1 -0
- package/dist/esm/index.js +1 -1
- package/dist/esm/server.js +2 -1
- package/dist/presets/barba.esm.js +55 -39
- package/dist/tether.account-pages.js +781 -495
- package/dist/tether.account-pages.min.js +1 -1
- package/dist/tether.account.js +462 -381
- package/dist/tether.account.min.js +1 -1
- package/dist/tether.analytics.js +299 -194
- package/dist/tether.analytics.min.js +1 -1
- package/dist/tether.diagnose.js +354 -262
- package/dist/tether.diagnose.min.js +2 -2
- package/dist/tether.extras.js +82 -45
- package/dist/tether.extras.min.js +1 -1
- package/dist/tether.js +3653 -2116
- package/dist/tether.markets.js +238 -150
- package/dist/tether.markets.min.js +1 -1
- package/dist/tether.min.js +3 -3
- package/dist/tether.min.js.map +4 -4
- package/dist/tether.search.js +207 -136
- package/dist/tether.search.min.js +1 -1
- package/dist/types/server/src/shared/account-orders.d.ts +44 -0
- package/dist/types/server/src/shared/account-routes.d.ts +153 -0
- package/dist/types/server/src/shared/api-versions.d.ts +13 -0
- package/dist/types/server/src/shared/error-message.d.ts +2 -0
- package/dist/types/server/src/shared/json.d.ts +25 -0
- package/dist/types/server/src/shared/market-codes.d.ts +16 -0
- package/dist/types/src/account/addresses-view.d.ts +5 -0
- package/dist/types/src/account/answers.d.ts +40 -0
- package/dist/types/src/account/markup.d.ts +19 -0
- package/dist/types/src/account/operations.d.ts +41 -0
- package/dist/types/src/account/order-lines.d.ts +13 -0
- package/dist/types/src/account/order-list.d.ts +12 -0
- package/dist/types/src/account/order-page.d.ts +6 -0
- package/dist/types/src/account/page-answers.d.ts +182 -0
- package/dist/types/src/account/page-events.d.ts +2 -0
- package/dist/types/src/account/server-client.d.ts +60 -0
- package/dist/types/src/account/subscriptions-view.d.ts +2 -0
- package/dist/types/src/account-api.d.ts +18 -0
- package/dist/types/src/account-marks.d.ts +15 -0
- package/dist/types/src/account-pages.d.ts +8 -0
- package/dist/types/src/account.d.ts +64 -0
- package/dist/types/src/amounts.d.ts +12 -0
- package/dist/types/src/analytics-shopify.d.ts +41 -0
- package/dist/types/src/analytics.d.ts +2 -0
- package/dist/types/src/api-version.d.ts +28 -0
- package/dist/types/src/astro.d.ts +42 -0
- package/dist/types/src/cart/cart-shape.d.ts +43 -0
- package/dist/types/src/cart/checkout.d.ts +16 -0
- package/dist/types/src/cart/drawer.d.ts +18 -0
- package/dist/types/src/cart/mutations.d.ts +79 -0
- package/dist/types/src/cart/render.d.ts +17 -0
- package/dist/types/src/cart/store.d.ts +182 -0
- package/dist/types/src/cart.d.ts +106 -0
- package/dist/types/src/client.d.ts +100 -0
- package/dist/types/src/collection.d.ts +25 -0
- package/dist/types/src/config-sections.d.ts +40 -0
- package/dist/types/src/config.d.ts +185 -0
- package/dist/types/src/controls/cart-controls.d.ts +2 -0
- package/dist/types/src/controls/discount.d.ts +2 -0
- package/dist/types/src/controls/extras.d.ts +5 -0
- package/dist/types/src/controls/navigation.d.ts +12 -0
- package/dist/types/src/diagnose-markup.d.ts +19 -0
- package/dist/types/src/diagnose.d.ts +60 -0
- package/dist/types/src/dom.d.ts +75 -0
- package/dist/types/src/extras.d.ts +21 -0
- package/dist/types/src/fragments.d.ts +158 -0
- package/dist/types/src/globals.d.ts +15 -0
- package/dist/types/src/images.d.ts +20 -0
- package/dist/types/src/index.d.ts +167 -0
- package/dist/types/src/initial.d.ts +56 -0
- package/dist/types/src/lazy.d.ts +28 -0
- package/dist/types/src/loader.d.ts +84 -0
- package/dist/types/src/market-codes.d.ts +6 -0
- package/dist/types/src/markets-ui.d.ts +32 -0
- package/dist/types/src/markets.d.ts +72 -0
- package/dist/types/src/markup.d.ts +131 -0
- package/dist/types/src/mounting.d.ts +46 -0
- package/dist/types/src/page-market.d.ts +27 -0
- package/dist/types/src/presets/barba.d.ts +56 -0
- package/dist/types/src/product-events.d.ts +2 -0
- package/dist/types/src/product-render.d.ts +17 -0
- package/dist/types/src/product-shape.d.ts +88 -0
- package/dist/types/src/product-state.d.ts +110 -0
- package/dist/types/src/product.d.ts +66 -0
- package/dist/types/src/repeaters.d.ts +16 -0
- package/dist/types/src/search.d.ts +33 -0
- package/dist/types/src/selling-plans.d.ts +64 -0
- package/dist/types/src/server.d.ts +88 -0
- package/dist/types/src/shopify-values.d.ts +46 -0
- package/dist/types/src/status.d.ts +33 -0
- package/dist/types/src/storage.d.ts +12 -0
- package/dist/types/src/store-html.d.ts +39 -0
- package/dist/types/src/storefront/catalog.d.ts +38 -0
- package/dist/types/src/storefront/json-ld.d.ts +20 -0
- package/dist/types/src/variant-render.d.ts +14 -0
- package/package.json +42 -22
- package/src/account/addresses-view.ts +58 -0
- package/src/account/answers.ts +79 -0
- package/src/account/markup.ts +36 -0
- package/src/account/operations.ts +145 -0
- package/src/account/order-lines.ts +75 -0
- package/src/account/order-list.ts +107 -0
- package/src/account/order-page.ts +137 -0
- package/src/account/page-answers.ts +317 -0
- package/src/account/page-events.ts +253 -0
- package/src/account/server-client.ts +183 -0
- package/src/account/subscriptions-view.ts +115 -0
- package/src/account-api.ts +98 -0
- package/src/account-marks.ts +35 -0
- package/src/account-pages.ts +81 -0
- package/src/account.ts +284 -0
- package/src/amounts.ts +64 -0
- package/src/analytics-shopify.ts +246 -0
- package/src/analytics.ts +315 -0
- package/src/api-version.ts +79 -0
- package/src/astro.ts +272 -0
- package/src/cart/cart-shape.ts +25 -0
- package/src/cart/checkout.ts +101 -0
- package/src/cart/drawer.ts +125 -0
- package/src/cart/mutations.ts +237 -0
- package/src/cart/render.ts +266 -0
- package/src/cart/store.ts +279 -0
- package/src/cart.ts +345 -0
- package/src/client.ts +391 -0
- package/src/collection.ts +175 -0
- package/src/config-sections.ts +284 -0
- package/src/config.ts +480 -0
- package/src/controls/cart-controls.ts +123 -0
- package/src/controls/discount.ts +75 -0
- package/src/controls/extras.ts +54 -0
- package/src/controls/navigation.ts +77 -0
- package/src/diagnose-markup.ts +298 -0
- package/src/diagnose.ts +294 -0
- package/src/dom.ts +268 -0
- package/src/extras.ts +136 -0
- package/src/fragments.ts +261 -0
- package/src/globals.d.ts +15 -0
- package/src/images.ts +91 -0
- package/src/index.ts +415 -0
- package/src/initial.ts +101 -0
- package/src/lazy-iife.ts +197 -0
- package/src/lazy.ts +42 -0
- package/src/loader.ts +363 -0
- package/src/market-codes.ts +6 -0
- package/src/markets-ui.ts +227 -0
- package/src/markets.ts +246 -0
- package/src/markup.ts +127 -0
- package/src/mounting.ts +264 -0
- package/src/page-market.ts +110 -0
- package/src/part-integrity.ts +7 -0
- package/src/parts/account-pages.ts +7 -0
- package/src/parts/account.ts +7 -0
- package/src/parts/analytics.ts +7 -0
- package/src/parts/diagnose.ts +7 -0
- package/src/parts/extras.ts +7 -0
- package/src/parts/markets.ts +7 -0
- package/src/parts/search.ts +7 -0
- package/src/presets/barba.ts +194 -0
- package/src/product-events.ts +115 -0
- package/src/product-render.ts +218 -0
- package/src/product-shape.ts +49 -0
- package/src/product-state.ts +318 -0
- package/src/product.ts +308 -0
- package/src/repeaters.ts +161 -0
- package/src/search.ts +305 -0
- package/src/selling-plans.ts +145 -0
- package/src/server.ts +211 -0
- package/src/shopify-values.ts +91 -0
- package/src/status.ts +106 -0
- package/src/storage.ts +34 -0
- package/src/store-html.ts +359 -0
- package/src/storefront/catalog.ts +196 -0
- package/src/storefront/json-ld.ts +144 -0
- package/src/variant-render.ts +139 -0
- package/dist/esm/chunks/account-Q6E2TFEV.js +0 -1
- package/dist/esm/chunks/account-pages-UZXR4R5F.js +0 -1
- package/dist/esm/chunks/analytics-IJBKATUP.js +0 -1
- package/dist/esm/chunks/chunk-4QJKLPYR.js +0 -1
- package/dist/esm/chunks/chunk-64TUD3QR.js +0 -1
- package/dist/esm/chunks/chunk-AJLPU2JC.js +0 -4
- package/dist/esm/chunks/chunk-FIOZPPC5.js +0 -1
- package/dist/esm/chunks/chunk-K2YEQAIH.js +0 -1
- package/dist/esm/chunks/chunk-KIDH76B7.js +0 -1
- package/dist/esm/chunks/chunk-PAYT5ZD7.js +0 -1
- package/dist/esm/chunks/chunk-RREHGH4A.js +0 -1
- package/dist/esm/chunks/chunk-SSJT43CJ.js +0 -1
- package/dist/esm/chunks/chunk-VC46IEJQ.js +0 -1
- package/dist/esm/chunks/diagnose-3WVAWNTX.js +0 -14
- package/dist/esm/chunks/extras-7I7WJX35.js +0 -1
- package/dist/esm/chunks/markets-ui-545XLFTE.js +0 -1
- package/dist/esm/chunks/search-NILMGYXG.js +0 -1
- package/src/account-pages.js +0 -318
- package/src/account.js +0 -385
- package/src/analytics.js +0 -232
- package/src/api-version.js +0 -35
- package/src/astro.js +0 -101
- package/src/cart.js +0 -559
- package/src/client.js +0 -131
- package/src/collection.js +0 -114
- package/src/config.js +0 -85
- package/src/diagnose.js +0 -246
- package/src/dom.js +0 -288
- package/src/extras.js +0 -63
- package/src/fragments.js +0 -144
- package/src/index.js +0 -395
- package/src/initial.js +0 -75
- package/src/lazy-iife.js +0 -46
- package/src/lazy.js +0 -18
- package/src/loader.js +0 -198
- package/src/markets-ui.js +0 -90
- package/src/markets.js +0 -133
- package/src/mounting.js +0 -154
- package/src/parts/account-pages.js +0 -3
- package/src/parts/account.js +0 -3
- package/src/parts/analytics.js +0 -3
- package/src/parts/diagnose.js +0 -3
- package/src/parts/extras.js +0 -3
- package/src/parts/markets.js +0 -3
- package/src/parts/search.js +0 -3
- package/src/presets/barba.js +0 -100
- package/src/product.js +0 -570
- package/src/search.js +0 -153
- package/src/selling-plans.js +0 -94
- package/src/server.js +0 -252
- package/src/status.js +0 -66
- package/types/astro.d.ts +0 -17
- package/types/barba.d.ts +0 -16
- package/types/index.d.ts +0 -426
- package/types/server.d.ts +0 -110
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
6
6
|
};
|
|
7
7
|
|
|
8
|
-
// src/account-pages.
|
|
8
|
+
// src/account-pages.ts
|
|
9
9
|
var account_pages_exports = {};
|
|
10
10
|
__export(account_pages_exports, {
|
|
11
11
|
addresses: () => addresses,
|
|
@@ -15,578 +15,864 @@
|
|
|
15
15
|
requestReturn: () => requestReturn,
|
|
16
16
|
saveAddress: () => saveAddress,
|
|
17
17
|
setup: () => setup,
|
|
18
|
+
showUnavailable: () => showUnavailable,
|
|
18
19
|
subscriptionAction: () => subscriptionAction,
|
|
19
20
|
subscriptions: () => subscriptions,
|
|
20
21
|
updateProfile: () => updateProfile
|
|
21
22
|
});
|
|
22
23
|
|
|
23
|
-
// tether-core:config.
|
|
24
|
-
var m = window.Tether.__core["config.
|
|
25
|
-
var
|
|
24
|
+
// tether-core:config.ts
|
|
25
|
+
var m = window.Tether.__core["config.ts"];
|
|
26
|
+
var [cfg, isConfigured, log, MARKET_SOURCES, parseMarkets, reportError, warn] = m;
|
|
26
27
|
|
|
27
|
-
// tether-core:
|
|
28
|
-
var m2 = window.Tether.__core["
|
|
29
|
-
var
|
|
28
|
+
// tether-core:dom.ts
|
|
29
|
+
var m2 = window.Tether.__core["dom.ts"];
|
|
30
|
+
var [ANALYTICS_EVENTS, attr, attributesFromJson, emit, formatDate, formatMoney, get, has, hasTemplate, isOwnEvent, parseJSONAttr, productUrl, qsa, repeat, sel, setImage, setText, show] = m2;
|
|
30
31
|
|
|
31
|
-
// tether-core:
|
|
32
|
-
var m3 = window.Tether.__core["
|
|
33
|
-
var
|
|
32
|
+
// tether-core:client.ts
|
|
33
|
+
var m3 = window.Tether.__core["client.ts"];
|
|
34
|
+
var [endpoint, gql, orNull, shaped, TetherError] = m3;
|
|
34
35
|
|
|
35
|
-
// server/src/account-
|
|
36
|
-
var
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
addressCreate: `mutation TetherAddressCreate($address:CustomerAddressInput!,$default:Boolean){customerAddressCreate(address:$address,defaultAddress:$default){customerAddress{${ADDRESS}}userErrors{field message}}}`,
|
|
47
|
-
addressUpdate: `mutation TetherAddressUpdate($id:ID!,$address:CustomerAddressInput,$default:Boolean){customerAddressUpdate(addressId:$id,address:$address,defaultAddress:$default){customerAddress{${ADDRESS}}userErrors{field message}}}`,
|
|
48
|
-
addressDelete: "mutation TetherAddressDelete($id: ID!) { customerAddressDelete(addressId: $id) { deletedAddressId userErrors { field message } } }",
|
|
49
|
-
pause: "mutation TetherPause($id: ID!) { subscriptionContractPause(subscriptionContractId: $id) { contract { id status } userErrors { field message } } }",
|
|
50
|
-
resume: "mutation TetherResume($id: ID!) { subscriptionContractActivate(subscriptionContractId: $id) { contract { id status } userErrors { field message } } }",
|
|
51
|
-
cancel: "mutation TetherCancel($id: ID!) { subscriptionContractCancel(subscriptionContractId: $id) { contract { id status } userErrors { field message } } }",
|
|
52
|
-
skip: "mutation TetherSkip($input: SubscriptionBillingCycleInput!) { subscriptionBillingCycleSkip(billingCycleInput: $input) { billingCycle { cycleIndex skipped } userErrors { field message } } }",
|
|
53
|
-
unskip: "mutation TetherUnskip($input: SubscriptionBillingCycleInput!) { subscriptionBillingCycleUnskip(billingCycleInput: $input) { billingCycle { cycleIndex skipped } userErrors { field message } } }",
|
|
54
|
-
returnRequest: "mutation TetherReturn($orderId: ID!, $lines: [RequestedLineItemInput!]!) { orderRequestReturn(orderId: $orderId, requestedLineItems: $lines) { return { id status } userErrors { field message } } }"
|
|
55
|
-
};
|
|
56
|
-
var InputError = class extends Error {
|
|
57
|
-
};
|
|
58
|
-
var gid = (type) => new RegExp(`^gid://shopify/${type}/\\d+(\\?[\\w=&.-]{1,80})?$`);
|
|
59
|
-
var IDS = {
|
|
60
|
-
Order: gid("Order"),
|
|
61
|
-
CustomerAddress: gid("CustomerAddress"),
|
|
62
|
-
SubscriptionContract: gid("SubscriptionContract"),
|
|
63
|
-
LineItem: gid("LineItem"),
|
|
64
|
-
ReturnReasonDefinition: gid("ReturnReasonDefinition")
|
|
65
|
-
};
|
|
66
|
-
function idOf(type, value) {
|
|
67
|
-
const v = /^\d{1,20}$/.test(String(value ?? "")) ? `gid://shopify/${type}/${value}` : String(value ?? "");
|
|
68
|
-
if (!IDS[type].test(v)) throw new InputError(`${type} id`);
|
|
69
|
-
return v;
|
|
70
|
-
}
|
|
71
|
-
var text = (v, max = 255) => {
|
|
72
|
-
if (v == null || v === "") return void 0;
|
|
73
|
-
if (typeof v !== "string" && typeof v !== "number") throw new InputError("text");
|
|
74
|
-
const s = String(v).replace(/[\u0000-\u001f\u007f]/g, "").trim();
|
|
75
|
-
if (s.length > max) throw new InputError("too long");
|
|
76
|
-
return s;
|
|
77
|
-
};
|
|
78
|
-
var ADDRESS_FIELDS = ["firstName", "lastName", "company", "address1", "address2", "city", "zip", "zoneCode", "phoneNumber"];
|
|
79
|
-
function addressInput(a = {}, { clear = false } = {}) {
|
|
80
|
-
if (!a || typeof a !== "object" || Array.isArray(a)) throw new InputError("address");
|
|
81
|
-
const out = {};
|
|
82
|
-
ADDRESS_FIELDS.forEach((k) => {
|
|
83
|
-
const v = text(a[k]);
|
|
84
|
-
if (v !== void 0) out[k] = v;
|
|
85
|
-
else if (clear && k in a && (a[k] === "" || a[k] === null)) out[k] = "";
|
|
86
|
-
});
|
|
87
|
-
if (a.countryCode != null && a.countryCode !== "") {
|
|
88
|
-
const c = String(a.countryCode).toUpperCase();
|
|
89
|
-
if (!/^[A-Z]{2}$/.test(c)) throw new InputError("countryCode");
|
|
90
|
-
out.countryCode = c;
|
|
91
|
-
}
|
|
92
|
-
return out;
|
|
93
|
-
}
|
|
94
|
-
var userErrors = (payload) => {
|
|
95
|
-
const errs = payload?.userErrors || [];
|
|
96
|
-
if (errs.length) {
|
|
97
|
-
const e = new InputError(errs.map((x) => x.message).join(" | "));
|
|
98
|
-
e.userErrors = errs;
|
|
99
|
-
throw e;
|
|
100
|
-
}
|
|
101
|
-
return payload;
|
|
102
|
-
};
|
|
103
|
-
var ops = {
|
|
104
|
-
async order(ask, { id }) {
|
|
105
|
-
const data = await ask(Q.order, { id: idOf("Order", id) });
|
|
106
|
-
return { order: data?.order || null };
|
|
107
|
-
},
|
|
108
|
-
async profile(ask, { firstName, lastName }) {
|
|
109
|
-
const input = {};
|
|
110
|
-
if (firstName !== void 0) input.firstName = text(firstName, 100) ?? "";
|
|
111
|
-
if (lastName !== void 0) input.lastName = text(lastName, 100) ?? "";
|
|
112
|
-
if (!Object.keys(input).length) throw new InputError("nothing to change");
|
|
113
|
-
const p = userErrors((await ask(M.profile, { input }))?.customerUpdate);
|
|
114
|
-
return { customer: p.customer };
|
|
115
|
-
},
|
|
116
|
-
async addresses(ask) {
|
|
117
|
-
const c = (await ask(Q.addresses, {}))?.customer;
|
|
118
|
-
const def = c?.defaultAddress?.id || null;
|
|
119
|
-
return { addresses: (c?.addresses?.nodes || []).map((a) => ({ ...a, isDefault: a.id === def })) };
|
|
120
|
-
},
|
|
121
|
-
async saveAddress(ask, { id, address, isDefault }) {
|
|
122
|
-
const a = addressInput(address || {}, { clear: Boolean(id) });
|
|
123
|
-
const def = isDefault === true ? true : void 0;
|
|
124
|
-
const p = id ? userErrors((await ask(M.addressUpdate, { id: idOf("CustomerAddress", id), address: Object.keys(a).length ? a : null, default: def ?? null }))?.customerAddressUpdate) : userErrors((await ask(M.addressCreate, { address: a, default: def ?? false }))?.customerAddressCreate);
|
|
125
|
-
return { address: p.customerAddress };
|
|
126
|
-
},
|
|
127
|
-
async deleteAddress(ask, { id }) {
|
|
128
|
-
const p = userErrors((await ask(M.addressDelete, { id: idOf("CustomerAddress", id) }))?.customerAddressDelete);
|
|
129
|
-
return { deleted: p.deletedAddressId };
|
|
36
|
+
// server/src/shared/account-routes.ts
|
|
37
|
+
var OPERATION_ROUTES = {
|
|
38
|
+
order: { name: "order", method: "GET", path: "/order", fields: { id: true } },
|
|
39
|
+
addresses: { name: "addresses", method: "GET", path: "/addresses", fields: {} },
|
|
40
|
+
subscriptions: { name: "subscriptions", method: "GET", path: "/subscriptions", fields: {} },
|
|
41
|
+
profile: { name: "profile", method: "POST", path: "/profile", fields: { firstName: true, lastName: true } },
|
|
42
|
+
saveAddress: {
|
|
43
|
+
name: "saveAddress",
|
|
44
|
+
method: "POST",
|
|
45
|
+
path: "/address",
|
|
46
|
+
fields: { id: true, address: true, isDefault: true }
|
|
130
47
|
},
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
}
|
|
134
|
-
async subscription(ask, { id, action }) {
|
|
135
|
-
if (!["pause", "resume", "skip", "unskip", "cancel"].includes(action)) throw new InputError("action");
|
|
136
|
-
const contractId = idOf("SubscriptionContract", id);
|
|
137
|
-
const contract = (await ask(Q.contract, { id: contractId }))?.customer?.subscriptionContract;
|
|
138
|
-
if (!contract) {
|
|
139
|
-
const e = new InputError("not found");
|
|
140
|
-
e.status = 404;
|
|
141
|
-
throw e;
|
|
142
|
-
}
|
|
143
|
-
if (action === "skip" || action === "unskip") {
|
|
144
|
-
const cycles = contract.upcomingBillingCycles?.nodes || [];
|
|
145
|
-
const cycle = action === "skip" ? cycles.find((c) => !c.skipped) : cycles.find((c) => c.skipped);
|
|
146
|
-
if (!cycle) throw new InputError(action === "skip" ? "no upcoming delivery to skip" : "nothing skipped");
|
|
147
|
-
const p2 = userErrors((await ask(M[action], { input: { contractId, selector: { index: cycle.cycleIndex } } }))?.[action === "skip" ? "subscriptionBillingCycleSkip" : "subscriptionBillingCycleUnskip"]);
|
|
148
|
-
return { billingCycle: p2.billingCycle };
|
|
149
|
-
}
|
|
150
|
-
const name = { pause: "subscriptionContractPause", resume: "subscriptionContractActivate", cancel: "subscriptionContractCancel" }[action];
|
|
151
|
-
const p = userErrors((await ask(M[action], { id: contractId }))?.[name]);
|
|
152
|
-
return { contract: p.contract };
|
|
153
|
-
},
|
|
154
|
-
async requestReturn(ask, { orderId, lines: lines2 }) {
|
|
155
|
-
const oid = idOf("Order", orderId);
|
|
156
|
-
if (!Array.isArray(lines2) || !lines2.length || lines2.length > 50) throw new InputError("lines");
|
|
157
|
-
const requested = lines2.map((l) => {
|
|
158
|
-
const q = Number(l?.quantity);
|
|
159
|
-
if (!Number.isInteger(q) || q < 1 || q > 1e3) throw new InputError("quantity");
|
|
160
|
-
const out = { lineItemId: idOf("LineItem", l.lineItemId), quantity: q };
|
|
161
|
-
if (l.reasonId) out.returnReasonDefinitionId = idOf("ReturnReasonDefinition", l.reasonId);
|
|
162
|
-
const note = text(l.note, 300);
|
|
163
|
-
if (note) out.customerNote = note;
|
|
164
|
-
return out;
|
|
165
|
-
});
|
|
166
|
-
const p = userErrors((await ask(M.returnRequest, { orderId: oid, lines: requested }))?.orderRequestReturn);
|
|
167
|
-
return { return: p.return };
|
|
168
|
-
}
|
|
48
|
+
deleteAddress: { name: "deleteAddress", method: "POST", path: "/address/delete", fields: { id: true } },
|
|
49
|
+
subscription: { name: "subscription", method: "POST", path: "/subscription", fields: { id: true, action: true } },
|
|
50
|
+
requestReturn: { name: "requestReturn", method: "POST", path: "/return", fields: { orderId: true, lines: true } }
|
|
169
51
|
};
|
|
52
|
+
var ROUTE_BY_REQUEST = new Map(
|
|
53
|
+
Object.values(OPERATION_ROUTES).map((route) => [
|
|
54
|
+
`${route.method} ${route.path}`,
|
|
55
|
+
{ ...route, fields: Object.keys(route.fields) }
|
|
56
|
+
])
|
|
57
|
+
);
|
|
58
|
+
function operationRequest(name, input) {
|
|
59
|
+
const route = OPERATION_ROUTES[name];
|
|
60
|
+
if (route.method === "POST") return { method: "POST", path: route.path };
|
|
61
|
+
const values = input;
|
|
62
|
+
const query = new URLSearchParams();
|
|
63
|
+
for (const fieldName of Object.keys(route.fields)) {
|
|
64
|
+
const value = values[fieldName];
|
|
65
|
+
if (typeof value === "string" || typeof value === "number") query.set(fieldName, String(value));
|
|
66
|
+
}
|
|
67
|
+
const search = query.toString();
|
|
68
|
+
return { method: "GET", path: search ? `${route.path}?${search}` : route.path };
|
|
69
|
+
}
|
|
170
70
|
|
|
171
|
-
// src/
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
function setup(c) {
|
|
175
|
-
ctx = c;
|
|
71
|
+
// server/src/shared/json.ts
|
|
72
|
+
function isRecord(value) {
|
|
73
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
176
74
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
75
|
+
function field(value, key) {
|
|
76
|
+
return isRecord(value) ? value[key] : void 0;
|
|
77
|
+
}
|
|
78
|
+
function asList(value) {
|
|
79
|
+
return Array.isArray(value) ? value : [];
|
|
80
|
+
}
|
|
81
|
+
function textOrNull(value) {
|
|
82
|
+
return typeof value === "string" && value !== "" ? value : null;
|
|
83
|
+
}
|
|
84
|
+
var numberOrNull = (value) => typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
85
|
+
var countOrZero = (value) => numberOrNull(value) ?? 0;
|
|
86
|
+
var listOf = (value, read) => asList(value).map((item) => read(item));
|
|
87
|
+
var nodesOf = (connection, read) => ({
|
|
88
|
+
nodes: listOf(field(connection, "nodes"), read)
|
|
89
|
+
});
|
|
90
|
+
var textList = (value) => listOf(value, textOrNull).filter((line) => line !== null);
|
|
91
|
+
|
|
92
|
+
// server/src/shared/account-orders.ts
|
|
93
|
+
function moneyOrNull(value) {
|
|
94
|
+
const amount = textOrNull(field(value, "amount"));
|
|
95
|
+
const currencyCode = textOrNull(field(value, "currencyCode"));
|
|
96
|
+
return amount === null || currencyCode === null ? null : { amount, currencyCode };
|
|
97
|
+
}
|
|
98
|
+
function imageOrNull(value) {
|
|
99
|
+
const url = textOrNull(field(value, "url"));
|
|
100
|
+
return url === null ? null : { url, altText: textOrNull(field(value, "altText")) };
|
|
101
|
+
}
|
|
102
|
+
var toOrderLine = (value) => ({
|
|
103
|
+
title: textOrNull(field(value, "title")),
|
|
104
|
+
variantTitle: textOrNull(field(value, "variantTitle")),
|
|
105
|
+
quantity: countOrZero(field(value, "quantity")),
|
|
106
|
+
image: imageOrNull(field(value, "image"))
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// src/account/answers.ts
|
|
110
|
+
var unexpected = (what) => new TetherError(`Customer accounts: the answer has no ${what}`);
|
|
111
|
+
function requiredId(value, what) {
|
|
112
|
+
const id = textOrNull(value);
|
|
113
|
+
if (!id) throw unexpected(what);
|
|
114
|
+
return id;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// src/account/page-answers.ts
|
|
118
|
+
function toMailingAddress(value) {
|
|
119
|
+
const text = (name) => textOrNull(field(value, name));
|
|
120
|
+
return {
|
|
121
|
+
id: text("id"),
|
|
122
|
+
firstName: text("firstName"),
|
|
123
|
+
lastName: text("lastName"),
|
|
124
|
+
company: text("company"),
|
|
125
|
+
address1: text("address1"),
|
|
126
|
+
address2: text("address2"),
|
|
127
|
+
city: text("city"),
|
|
128
|
+
province: text("province"),
|
|
129
|
+
zoneCode: text("zoneCode"),
|
|
130
|
+
zip: text("zip"),
|
|
131
|
+
country: text("country"),
|
|
132
|
+
countryCode: text("countryCode"),
|
|
133
|
+
phoneNumber: text("phoneNumber"),
|
|
134
|
+
formatted: textList(field(value, "formatted"))
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
var mailingAddressOrNull = (value) => isRecord(value) ? toMailingAddress(value) : null;
|
|
138
|
+
var toAccountAddress = (value) => ({
|
|
139
|
+
...toMailingAddress(value),
|
|
140
|
+
id: requiredId(field(value, "id"), "address id")
|
|
141
|
+
});
|
|
142
|
+
var toCustomerAddresses = (value) => listOf(value, (address) => ({ ...toAccountAddress(address), isDefault: field(address, "isDefault") === true }));
|
|
143
|
+
var toOrderDetailLine = (value) => ({
|
|
144
|
+
...toOrderLine(value),
|
|
145
|
+
id: requiredId(field(value, "id"), "line item id"),
|
|
146
|
+
name: textOrNull(field(value, "name")),
|
|
147
|
+
sku: textOrNull(field(value, "sku")),
|
|
148
|
+
price: moneyOrNull(field(value, "price")),
|
|
149
|
+
totalPrice: moneyOrNull(field(value, "totalPrice")),
|
|
150
|
+
suggestedReturnReasonDefinitions: nodesOf(field(value, "suggestedReturnReasonDefinitions"), (reason) => ({
|
|
151
|
+
id: requiredId(field(reason, "id"), "return reason id"),
|
|
152
|
+
name: textOrNull(field(reason, "name")),
|
|
153
|
+
handle: textOrNull(field(reason, "handle"))
|
|
154
|
+
}))
|
|
155
|
+
});
|
|
156
|
+
var toFulfillment = (value) => ({
|
|
157
|
+
id: textOrNull(field(value, "id")),
|
|
158
|
+
status: textOrNull(field(value, "status")),
|
|
159
|
+
createdAt: textOrNull(field(value, "createdAt")),
|
|
160
|
+
estimatedDeliveryAt: textOrNull(field(value, "estimatedDeliveryAt")),
|
|
161
|
+
latestShipmentStatus: textOrNull(field(value, "latestShipmentStatus")),
|
|
162
|
+
trackingInformation: listOf(field(value, "trackingInformation"), (tracking) => ({
|
|
163
|
+
company: textOrNull(field(tracking, "company")),
|
|
164
|
+
number: textOrNull(field(tracking, "number")),
|
|
165
|
+
url: textOrNull(field(tracking, "url"))
|
|
166
|
+
}))
|
|
167
|
+
});
|
|
168
|
+
function toReturnableLine(value) {
|
|
169
|
+
const lineId = textOrNull(field(field(value, "lineItem"), "id"));
|
|
170
|
+
return { quantity: countOrZero(field(value, "quantity")), lineItem: lineId === null ? null : { id: lineId } };
|
|
171
|
+
}
|
|
172
|
+
function toReturnInformation(value) {
|
|
173
|
+
if (!isRecord(value)) return null;
|
|
174
|
+
return { returnableLineItems: nodesOf(value["returnableLineItems"], toReturnableLine) };
|
|
175
|
+
}
|
|
176
|
+
function toOrderDetail(value) {
|
|
177
|
+
if (!isRecord(value)) return null;
|
|
178
|
+
const text = (name) => textOrNull(value[name]);
|
|
179
|
+
const money = (name) => moneyOrNull(value[name]);
|
|
180
|
+
const requiresShipping = value["requiresShipping"];
|
|
181
|
+
return {
|
|
182
|
+
id: requiredId(value["id"], "order id"),
|
|
183
|
+
name: text("name"),
|
|
184
|
+
number: numberOrNull(value["number"]),
|
|
185
|
+
processedAt: text("processedAt"),
|
|
186
|
+
cancelledAt: text("cancelledAt"),
|
|
187
|
+
financialStatus: text("financialStatus"),
|
|
188
|
+
fulfillmentStatus: text("fulfillmentStatus"),
|
|
189
|
+
statusPageUrl: text("statusPageUrl"),
|
|
190
|
+
requiresShipping: typeof requiresShipping === "boolean" ? requiresShipping : null,
|
|
191
|
+
totalPrice: money("totalPrice"),
|
|
192
|
+
subtotal: money("subtotal"),
|
|
193
|
+
totalShipping: money("totalShipping"),
|
|
194
|
+
totalTax: money("totalTax"),
|
|
195
|
+
shippingAddress: mailingAddressOrNull(value["shippingAddress"]),
|
|
196
|
+
billingAddress: mailingAddressOrNull(value["billingAddress"]),
|
|
197
|
+
lineItems: nodesOf(value["lineItems"], toOrderDetailLine),
|
|
198
|
+
fulfillments: nodesOf(value["fulfillments"], toFulfillment),
|
|
199
|
+
returnInformation: toReturnInformation(value["returnInformation"]),
|
|
200
|
+
returns: nodesOf(value["returns"], toReturn)
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
var toSubscriptionLine = (value) => ({
|
|
204
|
+
id: textOrNull(field(value, "id")),
|
|
205
|
+
name: textOrNull(field(value, "name")),
|
|
206
|
+
title: textOrNull(field(value, "title")),
|
|
207
|
+
variantTitle: textOrNull(field(value, "variantTitle")),
|
|
208
|
+
quantity: countOrZero(field(value, "quantity")),
|
|
209
|
+
sku: textOrNull(field(value, "sku")),
|
|
210
|
+
currentPrice: moneyOrNull(field(value, "currentPrice")),
|
|
211
|
+
lineDiscountedPrice: moneyOrNull(field(value, "lineDiscountedPrice")),
|
|
212
|
+
image: imageOrNull(field(value, "image"))
|
|
213
|
+
});
|
|
214
|
+
var toBillingCycle = (value) => ({
|
|
215
|
+
cycleIndex: numberOrNull(field(value, "cycleIndex")),
|
|
216
|
+
skipped: field(value, "skipped") === true,
|
|
217
|
+
billingAttemptExpectedDate: textOrNull(field(value, "billingAttemptExpectedDate"))
|
|
218
|
+
});
|
|
219
|
+
function toDeliveryPolicy(value) {
|
|
220
|
+
if (!isRecord(value)) return null;
|
|
221
|
+
const intervalCount = value["intervalCount"];
|
|
222
|
+
return {
|
|
223
|
+
interval: textOrNull(value["interval"]),
|
|
224
|
+
intervalCount: isRecord(intervalCount) ? { count: countOrZero(intervalCount["count"]) } : null
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
var toSubscriptionContract = (value) => ({
|
|
228
|
+
id: requiredId(field(value, "id"), "subscription id"),
|
|
229
|
+
status: textOrNull(field(value, "status")),
|
|
230
|
+
nextBillingDate: textOrNull(field(value, "nextBillingDate")),
|
|
231
|
+
currencyCode: textOrNull(field(value, "currencyCode")),
|
|
232
|
+
deliveryPrice: moneyOrNull(field(value, "deliveryPrice")),
|
|
233
|
+
deliveryPolicy: toDeliveryPolicy(field(value, "deliveryPolicy")),
|
|
234
|
+
lines: nodesOf(field(value, "lines"), toSubscriptionLine),
|
|
235
|
+
upcomingBillingCycles: nodesOf(field(value, "upcomingBillingCycles"), toBillingCycle)
|
|
236
|
+
});
|
|
237
|
+
var toSubscriptionContracts = (value) => listOf(value, toSubscriptionContract);
|
|
238
|
+
function toSubscriptionChange(result) {
|
|
239
|
+
const { contract, billingCycle } = result;
|
|
240
|
+
if (isRecord(contract)) {
|
|
241
|
+
return { contract: { id: textOrNull(contract["id"]), status: textOrNull(contract["status"]) } };
|
|
208
242
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
if (err instanceof InputError) throw new TetherError(err.message, { code: "INVALID", userErrors: err.userErrors });
|
|
213
|
-
throw err;
|
|
243
|
+
if (isRecord(billingCycle)) {
|
|
244
|
+
const { cycleIndex, skipped } = toBillingCycle(billingCycle);
|
|
245
|
+
return { billingCycle: { cycleIndex, skipped } };
|
|
214
246
|
}
|
|
247
|
+
throw unexpected("changed subscription");
|
|
248
|
+
}
|
|
249
|
+
function toReturn(value) {
|
|
250
|
+
return { id: requiredId(field(value, "id"), "return id"), status: textOrNull(field(value, "status")) };
|
|
215
251
|
}
|
|
216
|
-
var
|
|
217
|
-
|
|
252
|
+
var toDeletedId = (value) => requiredId(value, "deleted address id");
|
|
253
|
+
var toProfile = (value) => ({
|
|
254
|
+
firstName: textOrNull(field(value, "firstName")),
|
|
255
|
+
lastName: textOrNull(field(value, "lastName"))
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
// src/account/operations.ts
|
|
259
|
+
var context = null;
|
|
260
|
+
function setup(shared) {
|
|
261
|
+
context = shared;
|
|
262
|
+
}
|
|
263
|
+
function pagesContext() {
|
|
264
|
+
if (!context) throw new Error("account-pages: loaded without the account part");
|
|
265
|
+
return context;
|
|
266
|
+
}
|
|
267
|
+
async function run(name, input) {
|
|
268
|
+
const { serverFetch } = pagesContext();
|
|
269
|
+
const { method, path } = operationRequest(name, input);
|
|
270
|
+
const answer = await serverFetch(path, method === "POST" ? { method, body: input } : {});
|
|
271
|
+
if (answer.kind === "logged-out") throw new TetherError("Not logged in", { code: "NOT_LOGGED_IN", status: 401 });
|
|
272
|
+
return answer.data;
|
|
273
|
+
}
|
|
274
|
+
function changed(what) {
|
|
275
|
+
pagesContext().reset();
|
|
218
276
|
emit("account-updated", { what });
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
|
|
277
|
+
}
|
|
278
|
+
async function order(id) {
|
|
279
|
+
const result = await run("order", { id });
|
|
280
|
+
return toOrderDetail(result["order"]);
|
|
281
|
+
}
|
|
282
|
+
async function updateProfile({
|
|
283
|
+
firstName,
|
|
284
|
+
lastName
|
|
285
|
+
} = {}) {
|
|
286
|
+
const result = await run("profile", { firstName, lastName });
|
|
222
287
|
changed("profile");
|
|
223
|
-
return
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
|
|
288
|
+
return toProfile(result["customer"]);
|
|
289
|
+
}
|
|
290
|
+
async function addresses() {
|
|
291
|
+
const result = await run("addresses", {});
|
|
292
|
+
return toCustomerAddresses(result["addresses"]);
|
|
293
|
+
}
|
|
294
|
+
async function saveAddress(address, { id, isDefault } = {}) {
|
|
295
|
+
const result = await run("saveAddress", { id, address, isDefault });
|
|
227
296
|
changed("addresses");
|
|
228
|
-
return
|
|
229
|
-
}
|
|
230
|
-
|
|
297
|
+
return toAccountAddress(result["address"]);
|
|
298
|
+
}
|
|
299
|
+
async function deleteAddress(id) {
|
|
300
|
+
const result = await run("deleteAddress", { id });
|
|
231
301
|
changed("addresses");
|
|
232
|
-
return
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
|
|
302
|
+
return toDeletedId(result["deleted"]);
|
|
303
|
+
}
|
|
304
|
+
async function subscriptions() {
|
|
305
|
+
const result = await run("subscriptions", {});
|
|
306
|
+
return toSubscriptionContracts(result["subscriptions"]);
|
|
307
|
+
}
|
|
308
|
+
async function subscriptionAction(id, action) {
|
|
309
|
+
const result = await run("subscription", { id, action });
|
|
236
310
|
changed("subscriptions");
|
|
237
|
-
return
|
|
238
|
-
}
|
|
239
|
-
|
|
311
|
+
return toSubscriptionChange(result);
|
|
312
|
+
}
|
|
313
|
+
async function requestReturn(orderId, lines) {
|
|
314
|
+
const result = await run("requestReturn", { orderId, lines });
|
|
240
315
|
changed("orders");
|
|
241
|
-
return
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
var
|
|
246
|
-
|
|
247
|
-
|
|
316
|
+
return toReturn(result["return"]);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// tether-core:shopify-values.ts
|
|
320
|
+
var m4 = window.Tether.__core["shopify-values.ts"];
|
|
321
|
+
var [isHttpsUrl] = m4;
|
|
322
|
+
|
|
323
|
+
// src/account/markup.ts
|
|
324
|
+
function showIn(root, name, conditions) {
|
|
325
|
+
qsa(root, sel(name)).forEach((el) => {
|
|
326
|
+
const key = get(el, name) ?? "";
|
|
327
|
+
if (Object.hasOwn(conditions, key)) show(el, conditions[key] === true);
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
var bindsIn = (row, name) => qsa(row, sel(name)).concat(row.matches(sel(name)) ? [row] : []);
|
|
331
|
+
var enumText = (value) => value ? value.toLowerCase().replace(/_/g, " ") : "";
|
|
332
|
+
var addressText = (address) => (address?.formatted ?? []).join(", ");
|
|
333
|
+
var ownValue = (values, key) => Object.hasOwn(values, key) ? values[key] : void 0;
|
|
334
|
+
|
|
335
|
+
// src/account/order-lines.ts
|
|
336
|
+
var lineTexts = (line, returnable) => ({
|
|
337
|
+
title: line.title || line.name || "",
|
|
338
|
+
"variant-title": line.variantTitle || "",
|
|
339
|
+
quantity: String(line.quantity),
|
|
340
|
+
price: formatMoney(line.price),
|
|
341
|
+
total: formatMoney(line.totalPrice),
|
|
342
|
+
sku: line.sku || "",
|
|
343
|
+
returnable: returnable === null ? void 0 : String(returnable)
|
|
248
344
|
});
|
|
249
|
-
var
|
|
250
|
-
function
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
qsa(row, sel("return-quantity")).forEach((input) => {
|
|
265
|
-
input.max = String(can);
|
|
266
|
-
input.min = "0";
|
|
267
|
-
if (!input.value) input.value = "0";
|
|
268
|
-
input.disabled = can < 1;
|
|
345
|
+
var isInput = (el) => el.tagName === "INPUT";
|
|
346
|
+
function fillReturnControls(row, line, returnable) {
|
|
347
|
+
showIn(row, "order-line-show", { returnable: returnable > 0 });
|
|
348
|
+
qsa(row, sel("return-quantity")).forEach((input) => {
|
|
349
|
+
if (!isInput(input)) return;
|
|
350
|
+
input.max = String(returnable);
|
|
351
|
+
input.min = "0";
|
|
352
|
+
if (!input.value) input.value = "0";
|
|
353
|
+
input.disabled = returnable < 1;
|
|
354
|
+
});
|
|
355
|
+
qsa(row, `select${sel("return-reason")}`).forEach((select) => {
|
|
356
|
+
if (select.dataset["tetherFilled"] === line.id) return;
|
|
357
|
+
select.dataset["tetherFilled"] = line.id;
|
|
358
|
+
(line.suggestedReturnReasonDefinitions?.nodes ?? []).forEach((reason) => {
|
|
359
|
+
select.appendChild(new Option(reason.name ?? "", reason.id));
|
|
269
360
|
});
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
function fillLines(box, lines, returns) {
|
|
364
|
+
repeat(box, lines, (row, line) => {
|
|
365
|
+
const id = line.id;
|
|
366
|
+
const returnable = returns && id ? returns.get(id) ?? 0 : null;
|
|
367
|
+
if (id) row.dataset["tetherLine"] = id;
|
|
368
|
+
const texts = lineTexts(line, returnable);
|
|
369
|
+
bindsIn(row, "order-line").forEach((el) => {
|
|
370
|
+
const key = get(el, "order-line") ?? "";
|
|
371
|
+
if (key === "image") {
|
|
372
|
+
if (line.image) setImage(el, line.image.url, line.image.altText || line.title || "");
|
|
373
|
+
return;
|
|
275
374
|
}
|
|
375
|
+
const text = ownValue(texts, key);
|
|
376
|
+
if (text !== void 0) setText(el, text);
|
|
276
377
|
});
|
|
378
|
+
if (id && returnable !== null) fillReturnControls(row, { ...line, id }, returnable);
|
|
277
379
|
});
|
|
278
380
|
}
|
|
279
|
-
|
|
280
|
-
|
|
381
|
+
|
|
382
|
+
// src/account/order-page.ts
|
|
383
|
+
function orderKey(el) {
|
|
281
384
|
const raw = get(el, "order") || "";
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
385
|
+
if (!raw.startsWith("url:")) return raw;
|
|
386
|
+
return new URL(window.location.href).searchParams.get(raw.slice("url:".length) || "id");
|
|
387
|
+
}
|
|
388
|
+
function showOrderState(el, state) {
|
|
389
|
+
el.setAttribute(attr("order-state"), state);
|
|
390
|
+
showIn(el, "order-show", {
|
|
391
|
+
loading: state === "loading",
|
|
392
|
+
ready: false,
|
|
393
|
+
"not-found": state === "not-found",
|
|
394
|
+
error: state === "error"
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
var orderTexts = (detail) => ({
|
|
398
|
+
name: detail.name ?? "",
|
|
399
|
+
date: formatDate(detail.processedAt),
|
|
400
|
+
total: formatMoney(detail.totalPrice),
|
|
401
|
+
subtotal: formatMoney(detail.subtotal),
|
|
402
|
+
shipping: formatMoney(detail.totalShipping),
|
|
403
|
+
tax: formatMoney(detail.totalTax),
|
|
404
|
+
status: enumText(detail.financialStatus),
|
|
405
|
+
fulfillment: enumText(detail.fulfillmentStatus),
|
|
406
|
+
"shipping-address": addressText(detail.shippingAddress),
|
|
407
|
+
"billing-address": addressText(detail.billingAddress),
|
|
408
|
+
items: detail.lineItems.nodes.map((line) => `${String(line.quantity)}\xD7 ${line.title || line.name || ""}`).join(", "),
|
|
409
|
+
cancelled: formatDate(detail.cancelledAt)
|
|
410
|
+
});
|
|
411
|
+
function fillFulfillment(row, fulfillment) {
|
|
412
|
+
const tracking = fulfillment.trackingInformation[0];
|
|
413
|
+
const texts = {
|
|
414
|
+
status: enumText(fulfillment.latestShipmentStatus || fulfillment.status),
|
|
415
|
+
date: formatDate(fulfillment.createdAt),
|
|
416
|
+
eta: formatDate(fulfillment.estimatedDeliveryAt),
|
|
417
|
+
company: tracking?.company || "",
|
|
418
|
+
number: tracking?.number || ""
|
|
419
|
+
};
|
|
420
|
+
bindsIn(row, "fulfillment-bind").forEach((el) => {
|
|
421
|
+
const key = get(el, "fulfillment-bind") ?? "";
|
|
422
|
+
if (key === "url") {
|
|
423
|
+
const url = tracking?.url ?? null;
|
|
424
|
+
const linked = url !== null && isHttpsUrl(url);
|
|
425
|
+
if (linked) el.setAttribute("href", url);
|
|
426
|
+
show(el, linked);
|
|
312
427
|
return;
|
|
313
428
|
}
|
|
314
|
-
const
|
|
315
|
-
|
|
316
|
-
date: date(o.processedAt),
|
|
317
|
-
total: formatMoney(o.totalPrice),
|
|
318
|
-
subtotal: o.subtotal ? formatMoney(o.subtotal) : "",
|
|
319
|
-
shipping: o.totalShipping ? formatMoney(o.totalShipping) : "",
|
|
320
|
-
tax: o.totalTax ? formatMoney(o.totalTax) : "",
|
|
321
|
-
status: lower(o.financialStatus),
|
|
322
|
-
fulfillment: lower(o.fulfillmentStatus),
|
|
323
|
-
"shipping-address": lines(o.shippingAddress),
|
|
324
|
-
"billing-address": lines(o.billingAddress),
|
|
325
|
-
items: (o.lineItems?.nodes || []).map((l) => `${l.quantity}\xD7 ${l.title || l.name}`).join(", "),
|
|
326
|
-
cancelled: o.cancelledAt ? date(o.cancelledAt) : ""
|
|
327
|
-
}[k];
|
|
328
|
-
if (v != null) setText(b, v);
|
|
429
|
+
const text = ownValue(texts, key);
|
|
430
|
+
if (text !== void 0) setText(el, text);
|
|
329
431
|
});
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
432
|
+
}
|
|
433
|
+
function fillOrder(el, detail) {
|
|
434
|
+
const returnable = new Map(
|
|
435
|
+
(detail.returnInformation?.returnableLineItems.nodes ?? []).map((entry) => [
|
|
436
|
+
entry.lineItem?.id ?? "",
|
|
437
|
+
entry.quantity
|
|
438
|
+
])
|
|
439
|
+
);
|
|
440
|
+
const shipments = detail.fulfillments.nodes;
|
|
441
|
+
const texts = orderTexts(detail);
|
|
442
|
+
qsa(el, sel("order-bind")).forEach((bind) => {
|
|
443
|
+
const key = get(bind, "order-bind") ?? "";
|
|
444
|
+
if (key === "url") {
|
|
445
|
+
const statusPage = detail.statusPageUrl;
|
|
446
|
+
if (statusPage !== null && isHttpsUrl(statusPage)) bind.setAttribute("href", statusPage);
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
const text = ownValue(texts, key);
|
|
450
|
+
if (text !== void 0) setText(bind, text);
|
|
451
|
+
});
|
|
452
|
+
qsa(el, sel("order-lines")).forEach((box) => {
|
|
453
|
+
fillLines(box, detail.lineItems.nodes, returnable);
|
|
454
|
+
});
|
|
455
|
+
qsa(el, sel("order-fulfillments")).forEach((box) => {
|
|
456
|
+
repeat(box, shipments, fillFulfillment);
|
|
457
|
+
});
|
|
458
|
+
const returnRequested = el.dataset["tetherReturned"] === "1";
|
|
345
459
|
showIn(el, "order-show", {
|
|
346
460
|
loading: false,
|
|
347
461
|
ready: true,
|
|
348
462
|
error: false,
|
|
349
463
|
"not-found": false,
|
|
350
|
-
cancelled: Boolean(
|
|
351
|
-
shipped:
|
|
352
|
-
returnable: [...returnable.values()].some((
|
|
353
|
-
"has-returns":
|
|
354
|
-
"return-requested":
|
|
464
|
+
cancelled: Boolean(detail.cancelledAt),
|
|
465
|
+
shipped: shipments.length > 0,
|
|
466
|
+
returnable: [...returnable.values()].some((quantity) => quantity > 0),
|
|
467
|
+
"has-returns": !returnRequested && detail.returns.nodes.length > 0,
|
|
468
|
+
"return-requested": returnRequested
|
|
355
469
|
});
|
|
356
|
-
|
|
470
|
+
el.setAttribute(attr("order-state"), "ready");
|
|
357
471
|
}
|
|
358
|
-
async function
|
|
359
|
-
const
|
|
360
|
-
if (!
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
472
|
+
async function renderOrder(el) {
|
|
473
|
+
const key = orderKey(el);
|
|
474
|
+
if (!key) {
|
|
475
|
+
el.setAttribute(attr("order-state"), "not-found");
|
|
476
|
+
showIn(el, "order-show", { "not-found": true });
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
showOrderState(el, "loading");
|
|
480
|
+
let detail;
|
|
481
|
+
try {
|
|
482
|
+
detail = await order(key);
|
|
483
|
+
} catch (error) {
|
|
484
|
+
reportError(error, "order");
|
|
485
|
+
showOrderState(el, "error");
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
if (!detail) {
|
|
489
|
+
showOrderState(el, "not-found");
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
el.dataset["tetherOrderId"] = detail.id;
|
|
493
|
+
fillOrder(el, detail);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// src/account/addresses-view.ts
|
|
497
|
+
var shown = [];
|
|
498
|
+
var shownAddress = (id) => shown.find((address) => address.id === id);
|
|
499
|
+
var addressTexts = (address) => ({
|
|
500
|
+
formatted: addressText(address),
|
|
501
|
+
name: [address.firstName, address.lastName].filter(Boolean).join(" "),
|
|
502
|
+
company: address.company || "",
|
|
503
|
+
address1: address.address1 || "",
|
|
504
|
+
address2: address.address2 || "",
|
|
505
|
+
city: address.city || "",
|
|
506
|
+
zip: address.zip || "",
|
|
507
|
+
province: address.province || "",
|
|
508
|
+
country: address.country || "",
|
|
509
|
+
phone: address.phoneNumber || ""
|
|
510
|
+
});
|
|
511
|
+
function fillAddress(row, address) {
|
|
512
|
+
row.dataset["tetherAddress"] = address.id;
|
|
513
|
+
const texts = addressTexts(address);
|
|
514
|
+
bindsIn(row, "address-bind").forEach((el) => {
|
|
515
|
+
const text = ownValue(texts, get(el, "address-bind") ?? "");
|
|
516
|
+
if (text !== void 0) setText(el, text);
|
|
364
517
|
});
|
|
518
|
+
showIn(row, "address-show", { default: address.isDefault, "not-default": !address.isDefault });
|
|
365
519
|
}
|
|
366
|
-
var addressCache = null;
|
|
367
520
|
async function renderAddresses(root) {
|
|
368
521
|
const boxes = qsa(root, sel("addresses"));
|
|
369
522
|
if (!boxes.length) return;
|
|
370
|
-
|
|
523
|
+
showIn(root, "show", { "addresses-loading": true, "addresses-empty": false });
|
|
371
524
|
let list;
|
|
372
525
|
try {
|
|
373
|
-
list =
|
|
374
|
-
} catch (
|
|
375
|
-
reportError(
|
|
376
|
-
|
|
526
|
+
list = await addresses();
|
|
527
|
+
} catch (error) {
|
|
528
|
+
reportError(error, "addresses");
|
|
529
|
+
showIn(root, "show", { "addresses-loading": false, "addresses-error": true });
|
|
377
530
|
return;
|
|
378
531
|
}
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
if (v != null) setText(b, v);
|
|
385
|
-
});
|
|
386
|
-
showIn(row, "address-show", { default: a.isDefault, "not-default": !a.isDefault });
|
|
387
|
-
}));
|
|
532
|
+
shown = list;
|
|
533
|
+
showIn(root, "show", { "addresses-loading": false, "addresses-empty": list.length === 0, "addresses-error": false });
|
|
534
|
+
boxes.forEach((box) => {
|
|
535
|
+
repeat(box, list, fillAddress);
|
|
536
|
+
});
|
|
388
537
|
}
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
const
|
|
538
|
+
|
|
539
|
+
// src/account/subscriptions-view.ts
|
|
540
|
+
function conditionsOf(contract) {
|
|
541
|
+
const next = contract.upcomingBillingCycles.nodes[0];
|
|
542
|
+
const status = contract.status;
|
|
543
|
+
const active = status === "ACTIVE";
|
|
393
544
|
return {
|
|
394
|
-
active
|
|
395
|
-
paused:
|
|
396
|
-
cancelled:
|
|
397
|
-
expired:
|
|
398
|
-
failed:
|
|
545
|
+
active,
|
|
546
|
+
paused: status === "PAUSED",
|
|
547
|
+
cancelled: status === "CANCELLED",
|
|
548
|
+
expired: status === "EXPIRED",
|
|
549
|
+
failed: status === "FAILED",
|
|
399
550
|
skipped: Boolean(next?.skipped),
|
|
400
|
-
"can-pause":
|
|
401
|
-
"can-resume":
|
|
402
|
-
"can-skip":
|
|
403
|
-
"can-unskip":
|
|
404
|
-
"can-cancel":
|
|
551
|
+
"can-pause": active,
|
|
552
|
+
"can-resume": status === "PAUSED" || status === "FAILED",
|
|
553
|
+
"can-skip": active && next !== void 0 && !next.skipped,
|
|
554
|
+
"can-unskip": active && Boolean(next?.skipped),
|
|
555
|
+
"can-cancel": active || status === "PAUSED" || status === "FAILED"
|
|
405
556
|
};
|
|
406
557
|
}
|
|
558
|
+
function intervalText(contract) {
|
|
559
|
+
const unit = enumText(contract.deliveryPolicy?.interval);
|
|
560
|
+
if (!unit) return "";
|
|
561
|
+
const count = contract.deliveryPolicy?.intervalCount?.count ?? 1;
|
|
562
|
+
return count <= 1 ? unit : `${String(count)} ${unit}s`;
|
|
563
|
+
}
|
|
564
|
+
function contractTexts(contract) {
|
|
565
|
+
const lines = contract.lines.nodes;
|
|
566
|
+
const total = lines.reduce((sum, line) => sum + Number.parseFloat(line.lineDiscountedPrice?.amount ?? "0"), 0);
|
|
567
|
+
return {
|
|
568
|
+
status: enumText(contract.status),
|
|
569
|
+
next: formatDate(contract.nextBillingDate),
|
|
570
|
+
interval: intervalText(contract),
|
|
571
|
+
products: lines.map((line) => `${String(line.quantity)}\xD7 ${line.title ?? ""}`).join(", "),
|
|
572
|
+
total: formatMoney(
|
|
573
|
+
lines.length && contract.currencyCode ? { amount: String(total), currencyCode: contract.currencyCode } : null
|
|
574
|
+
),
|
|
575
|
+
delivery: formatMoney(contract.deliveryPrice)
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
function fillLine(row, line) {
|
|
579
|
+
const texts = {
|
|
580
|
+
title: line.title ?? "",
|
|
581
|
+
"variant-title": line.variantTitle || "",
|
|
582
|
+
quantity: String(line.quantity),
|
|
583
|
+
price: formatMoney(line.currentPrice)
|
|
584
|
+
};
|
|
585
|
+
bindsIn(row, "subscription-line").forEach((el) => {
|
|
586
|
+
const key = get(el, "subscription-line") ?? "";
|
|
587
|
+
if (key === "image") {
|
|
588
|
+
if (line.image) setImage(el, line.image.url, line.image.altText || line.title || "");
|
|
589
|
+
return;
|
|
590
|
+
}
|
|
591
|
+
const text = ownValue(texts, key);
|
|
592
|
+
if (text !== void 0) setText(el, text);
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
function fillContract(row, contract) {
|
|
596
|
+
row.dataset["tetherSubscription"] = contract.id;
|
|
597
|
+
row.setAttribute(attr("subscription-status"), enumText(contract.status));
|
|
598
|
+
const texts = contractTexts(contract);
|
|
599
|
+
qsa(row, sel("subscription-bind")).forEach((el) => {
|
|
600
|
+
const text = ownValue(texts, get(el, "subscription-bind") ?? "");
|
|
601
|
+
if (text !== void 0) setText(el, text);
|
|
602
|
+
});
|
|
603
|
+
qsa(row, sel("subscription-lines")).forEach((box) => {
|
|
604
|
+
repeat(box, contract.lines.nodes, fillLine);
|
|
605
|
+
});
|
|
606
|
+
const conditions = conditionsOf(contract);
|
|
607
|
+
showIn(row, "subscription-show", conditions);
|
|
608
|
+
qsa(row, sel("subscription-action")).forEach((button) => {
|
|
609
|
+
const allowed = ownValue(conditions, `can-${get(button, "subscription-action") ?? ""}`) === true;
|
|
610
|
+
if ("disabled" in button) button.disabled = !allowed;
|
|
611
|
+
button.classList.toggle("is-disabled", !allowed);
|
|
612
|
+
});
|
|
613
|
+
}
|
|
407
614
|
async function renderSubscriptions(root) {
|
|
408
615
|
const boxes = qsa(root, sel("subscriptions"));
|
|
409
616
|
if (!boxes.length) return;
|
|
410
|
-
|
|
617
|
+
showIn(root, "show", { "subscriptions-loading": true, "subscriptions-empty": false });
|
|
411
618
|
let list;
|
|
412
619
|
try {
|
|
413
620
|
list = await subscriptions();
|
|
414
|
-
} catch (
|
|
415
|
-
reportError(
|
|
416
|
-
|
|
621
|
+
} catch (error) {
|
|
622
|
+
reportError(error, "subscriptions");
|
|
623
|
+
showIn(root, "show", { "subscriptions-loading": false, "subscriptions-error": true });
|
|
417
624
|
return;
|
|
418
625
|
}
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
qsa(row, sel("subscription-bind")).forEach((b) => {
|
|
428
|
-
const k = get(b, "subscription-bind");
|
|
429
|
-
const v = {
|
|
430
|
-
status: lower(c.status),
|
|
431
|
-
next: c.nextBillingDate ? date(c.nextBillingDate) : "",
|
|
432
|
-
interval: unit ? n === 1 ? unit : `${n} ${unit}s` : "",
|
|
433
|
-
products: ls.map((l) => `${l.quantity}\xD7 ${l.title}`).join(", "),
|
|
434
|
-
total: ls.length ? formatMoney({ amount: String(total), currencyCode: c.currencyCode }) : "",
|
|
435
|
-
delivery: c.deliveryPrice ? formatMoney(c.deliveryPrice) : ""
|
|
436
|
-
}[k];
|
|
437
|
-
if (v != null) setText(b, v);
|
|
438
|
-
});
|
|
439
|
-
qsa(row, sel("subscription-lines")).forEach((lb) => repeat(lb, ls, (lr, l) => {
|
|
440
|
-
qsa(lr, sel("subscription-line")).concat(lr.matches(sel("subscription-line")) ? [lr] : []).forEach((b) => {
|
|
441
|
-
const k = get(b, "subscription-line");
|
|
442
|
-
if (k === "image") {
|
|
443
|
-
if (l.image) setImage(b, l.image.url, l.image.altText || l.title);
|
|
444
|
-
return;
|
|
445
|
-
}
|
|
446
|
-
const v = { title: l.title, "variant-title": l.variantTitle || "", quantity: String(l.quantity), price: formatMoney(l.currentPrice) }[k];
|
|
447
|
-
if (v != null) setText(b, v);
|
|
448
|
-
});
|
|
449
|
-
}));
|
|
450
|
-
const conds = subConds(c);
|
|
451
|
-
showIn(row, "subscription-show", conds);
|
|
452
|
-
qsa(row, sel("subscription-action")).forEach((btn) => {
|
|
453
|
-
const a = get(btn, "subscription-action");
|
|
454
|
-
const ok = conds[`can-${a}`];
|
|
455
|
-
btn.disabled = !ok;
|
|
456
|
-
btn.classList.toggle("is-disabled", !ok);
|
|
457
|
-
});
|
|
458
|
-
}));
|
|
626
|
+
showIn(root, "show", {
|
|
627
|
+
"subscriptions-loading": false,
|
|
628
|
+
"subscriptions-empty": list.length === 0,
|
|
629
|
+
"subscriptions-error": false
|
|
630
|
+
});
|
|
631
|
+
boxes.forEach((box) => {
|
|
632
|
+
repeat(box, list, fillContract);
|
|
633
|
+
});
|
|
459
634
|
}
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
635
|
+
|
|
636
|
+
// src/account/page-events.ts
|
|
637
|
+
var SUBSCRIPTION_ACTIONS = ["pause", "resume", "skip", "unskip", "cancel"];
|
|
638
|
+
var isSubscriptionAction = (value) => SUBSCRIPTION_ACTIONS.some((action) => action === value);
|
|
639
|
+
var isField = (el) => el instanceof window.HTMLInputElement || el instanceof window.HTMLSelectElement || el instanceof window.HTMLTextAreaElement;
|
|
640
|
+
var isForm = (el) => el instanceof window.HTMLFormElement;
|
|
641
|
+
function fieldsOf(form) {
|
|
642
|
+
const fields = {};
|
|
643
|
+
for (const field2 of form.elements) {
|
|
644
|
+
if (!isField(field2)) continue;
|
|
645
|
+
if (!field2.name || field2.type === "submit" || field2.type === "button" || field2.type === "checkbox") continue;
|
|
646
|
+
fields[field2.name] = field2.value;
|
|
464
647
|
}
|
|
465
|
-
|
|
466
|
-
...qsa(root, sel("order")).map((el) => renderOrder(el)),
|
|
467
|
-
...qsa(root, sel("profile-form")).map((f) => renderProfile(f)),
|
|
468
|
-
renderAddresses(root),
|
|
469
|
-
renderSubscriptions(root)
|
|
470
|
-
]);
|
|
648
|
+
return fields;
|
|
471
649
|
}
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
650
|
+
function customerMessage(error) {
|
|
651
|
+
const userErrors = error instanceof TetherError ? error.userErrors ?? [] : [];
|
|
652
|
+
const message = userErrors.map((userError) => userError.message).join(" ");
|
|
653
|
+
if (message) return message;
|
|
654
|
+
const text = error instanceof Error && error.message ? error.message : "Something went wrong";
|
|
655
|
+
return text.replace(/^Customer accounts: /, "");
|
|
656
|
+
}
|
|
657
|
+
async function act(el, change) {
|
|
658
|
+
if (el.getAttribute("aria-busy") === "true") return "busy";
|
|
475
659
|
el.classList.add("is-busy");
|
|
476
660
|
el.setAttribute("aria-busy", "true");
|
|
477
661
|
el.setAttribute(attr("form-state"), "pending");
|
|
478
|
-
qsa(el, sel("form-error"))
|
|
662
|
+
const errorBoxes = qsa(el, sel("form-error"));
|
|
663
|
+
errorBoxes.forEach((box) => {
|
|
664
|
+
setText(box, "");
|
|
665
|
+
});
|
|
479
666
|
try {
|
|
480
|
-
|
|
667
|
+
await change();
|
|
481
668
|
el.setAttribute(attr("form-state"), "saved");
|
|
482
|
-
return
|
|
483
|
-
} catch (
|
|
669
|
+
return "saved";
|
|
670
|
+
} catch (error) {
|
|
484
671
|
el.setAttribute(attr("form-state"), "error");
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
return
|
|
672
|
+
errorBoxes.forEach((box) => {
|
|
673
|
+
setText(box, customerMessage(error));
|
|
674
|
+
});
|
|
675
|
+
return "error";
|
|
489
676
|
} finally {
|
|
490
677
|
el.classList.remove("is-busy");
|
|
491
678
|
el.removeAttribute("aria-busy");
|
|
492
679
|
}
|
|
493
680
|
}
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
681
|
+
var confirmed = (button) => {
|
|
682
|
+
const question = get(button, "confirm");
|
|
683
|
+
return !question || window.confirm(question);
|
|
684
|
+
};
|
|
685
|
+
var addressFormReset = (form) => {
|
|
686
|
+
form.reset();
|
|
687
|
+
delete form.dataset["tetherAddressId"];
|
|
688
|
+
};
|
|
689
|
+
function onSubmit(event) {
|
|
690
|
+
const form = event.target;
|
|
691
|
+
if (!(form instanceof window.HTMLFormElement)) return;
|
|
692
|
+
if (form.matches(sel("profile-form"))) {
|
|
693
|
+
event.preventDefault();
|
|
694
|
+
void act(form, async () => {
|
|
695
|
+
await updateProfile(fieldsOf(form));
|
|
696
|
+
await pagesContext().bindCustomer(document);
|
|
697
|
+
});
|
|
698
|
+
} else if (form.matches(sel("address-form"))) {
|
|
699
|
+
event.preventDefault();
|
|
700
|
+
const id = form.dataset["tetherAddressId"];
|
|
701
|
+
const box = form.elements.namedItem("isDefault");
|
|
702
|
+
const isDefault = box instanceof window.HTMLInputElement && box.checked;
|
|
703
|
+
void act(form, async () => {
|
|
704
|
+
await saveAddress(fieldsOf(form), { id, isDefault });
|
|
705
|
+
addressFormReset(form);
|
|
706
|
+
await renderAddresses(document);
|
|
707
|
+
});
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
function editAddress(id) {
|
|
711
|
+
const address = shownAddress(id);
|
|
712
|
+
const form = document.querySelector(sel("address-form"));
|
|
713
|
+
if (!address || !form || !isForm(form)) return;
|
|
714
|
+
form.dataset["tetherAddressId"] = address.id;
|
|
715
|
+
const valuesByName = { ...address };
|
|
716
|
+
for (const field2 of form.elements) {
|
|
717
|
+
if (!isField(field2)) continue;
|
|
718
|
+
if (field2.name === "isDefault") {
|
|
719
|
+
if (field2 instanceof window.HTMLInputElement) field2.checked = address.isDefault;
|
|
720
|
+
} else if (field2.name && Object.hasOwn(valuesByName, field2.name)) {
|
|
721
|
+
const value = valuesByName[field2.name];
|
|
722
|
+
field2.value = typeof value === "string" ? value : "";
|
|
513
723
|
}
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
|
|
724
|
+
}
|
|
725
|
+
form.scrollIntoView({ block: "nearest" });
|
|
726
|
+
}
|
|
727
|
+
function onAddressClick(event, target) {
|
|
728
|
+
const row = target.closest("[data-tether-address]");
|
|
729
|
+
const id = row instanceof window.HTMLElement ? row.dataset["tetherAddress"] : void 0;
|
|
730
|
+
if (target.closest(sel("address-new"))) {
|
|
731
|
+
const form = document.querySelector(sel("address-form"));
|
|
732
|
+
if (form && isForm(form)) addressFormReset(form);
|
|
733
|
+
return true;
|
|
734
|
+
}
|
|
735
|
+
if (!(row instanceof window.HTMLElement) || !id) return false;
|
|
736
|
+
const deleteButton = target.closest(sel("address-delete"));
|
|
737
|
+
if (deleteButton) {
|
|
738
|
+
event.preventDefault();
|
|
739
|
+
if (!confirmed(deleteButton)) return true;
|
|
740
|
+
void act(row, async () => {
|
|
741
|
+
await deleteAddress(id);
|
|
742
|
+
await renderAddresses(document);
|
|
743
|
+
});
|
|
744
|
+
} else if (target.closest(sel("address-default"))) {
|
|
745
|
+
event.preventDefault();
|
|
746
|
+
void act(row, async () => {
|
|
747
|
+
await saveAddress(null, { id, isDefault: true });
|
|
748
|
+
await renderAddresses(document);
|
|
749
|
+
});
|
|
750
|
+
} else if (target.closest(sel("address-edit"))) {
|
|
751
|
+
event.preventDefault();
|
|
752
|
+
editAddress(id);
|
|
753
|
+
} else {
|
|
754
|
+
return false;
|
|
755
|
+
}
|
|
756
|
+
return true;
|
|
757
|
+
}
|
|
758
|
+
function onSubscriptionAction(button) {
|
|
759
|
+
const row = button.closest("[data-tether-subscription]");
|
|
760
|
+
const action = get(button, "subscription-action");
|
|
761
|
+
const disabled = "disabled" in button && button.disabled === true || button.classList.contains("is-disabled");
|
|
762
|
+
if (!(row instanceof window.HTMLElement) || !isSubscriptionAction(action) || disabled || !confirmed(button)) return;
|
|
763
|
+
const id = row.dataset["tetherSubscription"] ?? "";
|
|
764
|
+
row.setAttribute(attr("subscription-state"), "pending");
|
|
765
|
+
void act(row, async () => {
|
|
766
|
+
await subscriptionAction(id, action);
|
|
767
|
+
await renderSubscriptions(document);
|
|
768
|
+
}).then((outcome) => {
|
|
769
|
+
const state = outcome === "error" ? "error" : "done";
|
|
770
|
+
qsa(document, "[data-tether-subscription]").filter((candidate) => candidate === row || candidate.dataset["tetherSubscription"] === id).forEach((candidate) => {
|
|
771
|
+
candidate.setAttribute(attr("subscription-state"), state);
|
|
772
|
+
});
|
|
517
773
|
});
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
});
|
|
570
|
-
} else if (btn = t.closest?.(sel("order-return"))) {
|
|
571
|
-
e.preventDefault();
|
|
572
|
-
const scope = btn.closest(SCOPE.order);
|
|
573
|
-
if (!scope?.dataset.tetherOrderId) return;
|
|
574
|
-
const req = qsa(scope, "[data-tether-line]").map((r) => ({
|
|
575
|
-
lineItemId: r.dataset.tetherLine,
|
|
576
|
-
quantity: parseInt(r.querySelector(sel("return-quantity"))?.value || "0", 10),
|
|
577
|
-
reasonId: r.querySelector(sel("return-reason"))?.value || void 0,
|
|
578
|
-
note: r.querySelector(sel("return-note"))?.value || void 0
|
|
579
|
-
})).filter((l) => l.quantity > 0);
|
|
580
|
-
if (!req.length || !confirmOk(btn)) return;
|
|
581
|
-
act(scope, async () => {
|
|
582
|
-
await requestReturn(scope.dataset.tetherOrderId, req);
|
|
583
|
-
scope.dataset.tetherReturned = "1";
|
|
584
|
-
await renderOrder(scope);
|
|
585
|
-
});
|
|
774
|
+
}
|
|
775
|
+
function returnLineOf(row) {
|
|
776
|
+
const quantity = row.querySelector(sel("return-quantity"));
|
|
777
|
+
const reason = row.querySelector(sel("return-reason"));
|
|
778
|
+
const note = row.querySelector(sel("return-note"));
|
|
779
|
+
const valueOf = (field2) => field2 && "value" in field2 && typeof field2.value === "string" ? field2.value : "";
|
|
780
|
+
const line = {
|
|
781
|
+
lineItemId: row.dataset["tetherLine"] ?? "",
|
|
782
|
+
quantity: Number.parseInt(valueOf(quantity) || "0", 10)
|
|
783
|
+
};
|
|
784
|
+
const reasonId = valueOf(reason);
|
|
785
|
+
if (reasonId) line.reasonId = reasonId;
|
|
786
|
+
const noteText = valueOf(note);
|
|
787
|
+
if (noteText) line.note = noteText;
|
|
788
|
+
return line;
|
|
789
|
+
}
|
|
790
|
+
function onReturnRequest(button) {
|
|
791
|
+
const scope = button.closest(sel("order"));
|
|
792
|
+
if (!(scope instanceof window.HTMLElement)) return;
|
|
793
|
+
const orderId = scope.dataset["tetherOrderId"];
|
|
794
|
+
if (!orderId) return;
|
|
795
|
+
const lines = qsa(scope, "[data-tether-line]").map(returnLineOf).filter((line) => line.quantity > 0);
|
|
796
|
+
if (!lines.length || !confirmed(button)) return;
|
|
797
|
+
void act(scope, async () => {
|
|
798
|
+
await requestReturn(orderId, lines);
|
|
799
|
+
scope.dataset["tetherReturned"] = "1";
|
|
800
|
+
await renderOrder(scope);
|
|
801
|
+
});
|
|
802
|
+
}
|
|
803
|
+
function onClick(event) {
|
|
804
|
+
const target = event.target;
|
|
805
|
+
if (!(target instanceof window.Element)) return;
|
|
806
|
+
if (onAddressClick(event, target)) return;
|
|
807
|
+
const subscriptionButton = target.closest(sel("subscription-action"));
|
|
808
|
+
if (subscriptionButton instanceof window.HTMLElement) {
|
|
809
|
+
event.preventDefault();
|
|
810
|
+
onSubscriptionAction(subscriptionButton);
|
|
811
|
+
return;
|
|
812
|
+
}
|
|
813
|
+
const returnButton = target.closest(sel("order-return"));
|
|
814
|
+
if (returnButton instanceof window.HTMLElement) {
|
|
815
|
+
event.preventDefault();
|
|
816
|
+
onReturnRequest(returnButton);
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
function listenToPages() {
|
|
820
|
+
document.addEventListener("submit", onSubmit, true);
|
|
821
|
+
document.addEventListener("input", (event) => {
|
|
822
|
+
const target = event.target;
|
|
823
|
+
if (target instanceof window.HTMLElement && target.closest(sel("profile-form"))) {
|
|
824
|
+
target.dataset["tetherTouched"] = "1";
|
|
586
825
|
}
|
|
587
826
|
});
|
|
827
|
+
document.addEventListener("click", onClick);
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
// src/account-pages.ts
|
|
831
|
+
var PROFILE_FIELDS = ["firstName", "lastName"];
|
|
832
|
+
async function renderProfile(form) {
|
|
833
|
+
if (!(form instanceof window.HTMLFormElement)) return;
|
|
834
|
+
let customer;
|
|
835
|
+
try {
|
|
836
|
+
customer = await pagesContext().customer();
|
|
837
|
+
} catch (error) {
|
|
838
|
+
reportError(error, "account");
|
|
839
|
+
return;
|
|
840
|
+
}
|
|
841
|
+
if (!customer) return;
|
|
842
|
+
const fields = form.elements;
|
|
843
|
+
PROFILE_FIELDS.forEach((name) => {
|
|
844
|
+
const input = fields.namedItem(name);
|
|
845
|
+
const isTextField = input instanceof window.HTMLInputElement || input instanceof window.HTMLTextAreaElement;
|
|
846
|
+
if (isTextField && !input.dataset["tetherTouched"]) input.value = customer[name] ?? "";
|
|
847
|
+
});
|
|
848
|
+
}
|
|
849
|
+
var listening = false;
|
|
850
|
+
async function renderPages(root = document) {
|
|
851
|
+
if (!listening) {
|
|
852
|
+
listening = true;
|
|
853
|
+
listenToPages();
|
|
854
|
+
}
|
|
855
|
+
await Promise.all([
|
|
856
|
+
...qsa(root, sel("order")).map((el) => renderOrder(el)),
|
|
857
|
+
...qsa(root, sel("profile-form")).map((form) => renderProfile(form)),
|
|
858
|
+
renderAddresses(root),
|
|
859
|
+
renderSubscriptions(root)
|
|
860
|
+
]);
|
|
861
|
+
}
|
|
862
|
+
function showUnavailable(root) {
|
|
863
|
+
qsa(root, sel("order")).forEach((el) => {
|
|
864
|
+
showOrderState(el, "error");
|
|
865
|
+
});
|
|
866
|
+
showIn(root, "show", {
|
|
867
|
+
"addresses-loading": false,
|
|
868
|
+
"addresses-error": true,
|
|
869
|
+
"subscriptions-loading": false,
|
|
870
|
+
"subscriptions-error": true
|
|
871
|
+
});
|
|
588
872
|
}
|
|
589
873
|
|
|
590
|
-
// src/parts/account-pages.
|
|
591
|
-
|
|
874
|
+
// src/parts/account-pages.ts
|
|
875
|
+
var { Tether } = window;
|
|
876
|
+
if (!Tether) throw new Error("tether.account-pages.js runs after the Tether script, which loads it");
|
|
877
|
+
Tether.__parts["account-pages"] = account_pages_exports;
|
|
592
878
|
})();
|