@occluze/tether 0.6.6 → 0.6.8

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