@occluze/tether 0.6.7 → 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 +773 -442
  26. package/dist/tether.account-pages.min.js +1 -1
  27. package/dist/tether.account.js +648 -318
  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 +331 -242
  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 +3176 -2015
  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 +69 -298
  58. package/src/account.js +280 -323
  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 +320 -488
  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 -287
  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-Q6E2TFEV.js +0 -1
  120. package/dist/esm/chunks/account-pages-UZXR4R5F.js +0 -1
  121. package/dist/esm/chunks/analytics-IJBKATUP.js +0 -1
  122. package/dist/esm/chunks/chunk-4QJKLPYR.js +0 -1
  123. package/dist/esm/chunks/chunk-64TUD3QR.js +0 -1
  124. package/dist/esm/chunks/chunk-AJLPU2JC.js +0 -4
  125. package/dist/esm/chunks/chunk-FIOZPPC5.js +0 -1
  126. package/dist/esm/chunks/chunk-K2YEQAIH.js +0 -1
  127. package/dist/esm/chunks/chunk-KIDH76B7.js +0 -1
  128. package/dist/esm/chunks/chunk-PAYT5ZD7.js +0 -1
  129. package/dist/esm/chunks/chunk-RREHGH4A.js +0 -1
  130. package/dist/esm/chunks/chunk-SSJT43CJ.js +0 -1
  131. package/dist/esm/chunks/chunk-VC46IEJQ.js +0 -1
  132. package/dist/esm/chunks/diagnose-3WVAWNTX.js +0 -14
  133. package/dist/esm/chunks/extras-7I7WJX35.js +0 -1
  134. package/dist/esm/chunks/markets-ui-545XLFTE.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,174 +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 = {}, { clear = false } = {}) {
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
- 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;
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;
91
150
  }
92
151
  return out;
93
152
  }
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;
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 });
100
162
  }
101
163
  return payload;
102
- };
164
+ }
103
165
  var ops = {
104
166
  async order(ask, { id }) {
105
- const data = await ask(Q.order, { id: idOf("Order", id) });
106
- return { order: data?.order || null };
167
+ const data = await ask(QUERIES.order, { id: idOf("Order", id) });
168
+ return { order: field(data, "order") ?? null };
107
169
  },
108
170
  async profile(ask, { firstName, lastName }) {
109
171
  const input = {};
110
- if (firstName !== void 0) input.firstName = text(firstName, 100) ?? "";
111
- 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) ?? "";
112
174
  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 };
175
+ const payload = payloadOf(await ask(MUTATIONS.profile, { input }), "customerUpdate");
176
+ return { customer: field(payload, "customer") };
115
177
  },
116
178
  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 })) };
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 };
120
187
  },
121
188
  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 };
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") };
126
201
  },
127
202
  async deleteAddress(ask, { id }) {
128
- const p = userErrors((await ask(M.addressDelete, { id: idOf("CustomerAddress", id) }))?.customerAddressDelete);
129
- return { deleted: p.deletedAddressId };
203
+ const data = await ask(MUTATIONS.addressDelete, { id: idOf("CustomerAddress", id) });
204
+ return { deleted: field(payloadOf(data, "customerAddressDelete"), "deletedAddressId") };
130
205
  },
131
206
  async subscriptions(ask) {
132
- 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) };
133
209
  },
134
210
  async subscription(ask, { id, action }) {
135
- if (!["pause", "resume", "skip", "unskip", "cancel"].includes(action)) throw new InputError("action");
211
+ if (!isSubscriptionAction(action)) throw new InputError("action");
136
212
  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 };
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") };
149
218
  }
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 };
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") };
153
225
  },
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;
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;
164
237
  return out;
165
238
  });
166
- const p = userErrors((await ask(M.returnRequest, { orderId: oid, lines: requested }))?.orderRequestReturn);
167
- return { return: p.return };
239
+ const data = await ask(MUTATIONS.returnRequest, { orderId: order2, lines: requested });
240
+ return { return: field(payloadOf(data, "orderRequestReturn"), "return") };
168
241
  }
169
242
  };
170
243
 
171
- // src/account-pages.js
172
- var ctx = null;
173
- var bound = false;
174
- function setup(c) {
175
- 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;
176
252
  }
177
- var https = (u) => {
178
- try {
179
- return new URL(u).protocol === "https:";
180
- } catch {
181
- return false;
182
- }
183
- };
184
- var date = (s) => {
185
- try {
186
- return new Date(s).toLocaleDateString(cfg.locale || void 0);
187
- } catch {
188
- return s;
189
- }
190
- };
191
253
  var ROUTE = {
192
- order: (i) => ["GET", `/order?id=${encodeURIComponent(i.id)}`],
254
+ order: (input) => ["GET", `/order?id=${encodeURIComponent(String(input["id"]))}`],
193
255
  addresses: () => ["GET", "/addresses"],
194
256
  subscriptions: () => ["GET", "/subscriptions"],
195
257
  profile: () => ["POST", "/profile"],
@@ -199,394 +261,663 @@
199
261
  requestReturn: () => ["POST", "/return"]
200
262
  };
201
263
  async function run(name, input = {}) {
202
- const { server, serverFetch, query } = ctx;
203
- if (server()) {
264
+ const { serverBase, serverFetch, query } = pagesContext();
265
+ if (serverBase()) {
204
266
  const [method, path] = ROUTE[name](input);
205
- const data = await serverFetch(path, method === "POST" ? { method, body: input } : {});
206
- if (data.loggedIn === false) throw new TetherError("Not logged in", { code: "NOT_LOGGED_IN", status: 401 });
207
- 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;
208
270
  }
271
+ const operation = ops[name];
272
+ if (!operation) throw new TetherError(`Customer accounts: no operation ${name}`);
209
273
  try {
210
- return await ops[name]((q, v) => query(q, v), input);
211
- } catch (err) {
212
- if (err instanceof InputError) throw new TetherError(err.message, { code: "INVALID", userErrors: err.userErrors });
213
- 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 });
214
284
  }
215
285
  }
216
- var changed = (what) => {
217
- ctx.reset();
286
+ function changed(what) {
287
+ pagesContext().reset();
218
288
  emit("account-updated", { what });
219
- };
220
- var order = (id) => run("order", { id }).then((r) => r.order);
221
- 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 });
222
299
  changed("profile");
223
- return r.customer;
224
- });
225
- var addresses = () => run("addresses").then((r) => r.addresses);
226
- 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 });
227
314
  changed("addresses");
228
- return r.address;
229
- });
230
- 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 });
231
322
  changed("addresses");
232
- return r.deleted;
233
- });
234
- var subscriptions = () => run("subscriptions").then((r) => r.subscriptions);
235
- 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 });
236
337
  changed("subscriptions");
237
- return r;
238
- });
239
- 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 });
240
342
  changed("orders");
241
- return r.return;
242
- });
243
- var lower = (v) => v ? String(v).toLowerCase().replace(/_/g, " ") : "";
244
- var lines = (a) => (a?.formatted || []).join(", ");
245
- var showIn = (root, name, conds) => qsa(root, sel(name)).forEach((el) => {
246
- const k = get(el, name);
247
- 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)
248
384
  });
249
- var showGlobal = (root, conds) => showIn(root, "show", conds);
250
- function fillLines(box, items, returnable = null) {
251
- repeat(box, items, (row, l) => {
252
- const can = returnable ? returnable.get(l.id) || 0 : 0;
253
- row.dataset.tetherLine = l.id;
254
- qsa(row, sel("order-line")).concat(row.matches(sel("order-line")) ? [row] : []).forEach((el) => {
255
- const k = get(el, "order-line");
256
- if (k === "image") {
257
- if (l.image) setImage(el, l.image.url, l.image.altText || l.title);
258
- return;
259
- }
260
- 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];
261
- if (v != null) setText(el, v);
262
- });
263
- showIn(row, "order-line-show", { returnable: can > 0 });
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;
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));
269
400
  });
270
- qsa(row, `select${sel("return-reason")}`).forEach((select) => {
271
- const reasons = l.suggestedReturnReasonDefinitions?.nodes || [];
272
- if (select.dataset.tetherFilled !== l.id) {
273
- select.dataset.tetherFilled = l.id;
274
- 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;
275
414
  }
415
+ const text2 = ownValue(texts, key);
416
+ if (text2 !== void 0) setText(el, text2);
276
417
  });
418
+ if (id && returnable !== null) fillReturnControls(row, { ...line, id }, returnable);
277
419
  });
278
420
  }
279
- var SCOPE = { order: sel("order") };
280
- async function renderOrder(el) {
421
+
422
+ // src/account/order-page.js
423
+ function orderKey(el) {
281
424
  const raw = get(el, "order") || "";
282
- const key = raw.startsWith("url:") ? new URL(window.location.href).searchParams.get(raw.slice(4) || "id") : raw;
283
- const state = (s) => el.setAttribute(attr("order-state"), s);
284
- if (!key) {
285
- state("not-found");
286
- showIn(el, "order-show", { "not-found": true });
287
- return;
288
- }
289
- state("loading");
290
- showIn(el, "order-show", { loading: true, ready: false, "not-found": false, error: false });
291
- let o;
292
- try {
293
- o = await order(key);
294
- } catch (err) {
295
- reportError(err, "order");
296
- state("error");
297
- showIn(el, "order-show", { loading: false, error: true });
298
- return;
299
- }
300
- if (!o) {
301
- state("not-found");
302
- showIn(el, "order-show", { loading: false, "not-found": true });
303
- return;
304
- }
305
- el.dataset.tetherOrderId = o.id;
306
- const returnable = new Map((o.returnInformation?.returnableLineItems?.nodes || []).map((r) => [r.lineItem?.id, r.quantity]));
307
- const ships = o.fulfillments?.nodes || [];
308
- qsa(el, sel("order-bind")).forEach((b) => {
309
- const k = get(b, "order-bind");
310
- if (k === "url") {
311
- 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);
312
467
  return;
313
468
  }
314
- const v = {
315
- name: o.name,
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);
469
+ const text2 = ownValue(texts, key);
470
+ if (text2 !== void 0) setText(el, text2);
329
471
  });
330
- qsa(el, sel("order-lines")).forEach((box) => fillLines(box, o.lineItems?.nodes || [], returnable));
331
- qsa(el, sel("order-fulfillments")).forEach((box) => repeat(box, ships, (row, f) => {
332
- const t = f.trackingInformation?.[0] || {};
333
- qsa(row, sel("fulfillment-bind")).concat(row.matches(sel("fulfillment-bind")) ? [row] : []).forEach((b) => {
334
- const k = get(b, "fulfillment-bind");
335
- if (k === "url") {
336
- const ok = https(t.url);
337
- if (ok) b.setAttribute("href", t.url);
338
- show(b, ok);
339
- return;
340
- }
341
- 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];
342
- if (v != null) setText(b, v);
343
- });
344
- }));
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";
345
498
  showIn(el, "order-show", {
346
499
  loading: false,
347
500
  ready: true,
348
501
  error: false,
349
502
  "not-found": false,
350
- cancelled: Boolean(o.cancelledAt),
351
- shipped: ships.length > 0,
352
- returnable: [...returnable.values()].some((q) => q > 0),
353
- "has-returns": el.dataset.tetherReturned !== "1" && (o.returns?.nodes || []).length > 0,
354
- "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
355
508
  });
356
- state("ready");
509
+ el.setAttribute(attr("order-state"), "ready");
357
510
  }
358
- async function renderProfile(form) {
359
- const c = await ctx.customer().catch(() => null);
360
- if (!c) return;
361
- ["firstName", "lastName"].forEach((n) => {
362
- const i = form.elements?.[n];
363
- 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);
364
556
  });
557
+ showIn(row, "address-show", { default: address.isDefault, "not-default": !address.isDefault });
365
558
  }
366
- var addressCache = null;
367
559
  async function renderAddresses(root) {
368
560
  const boxes = qsa(root, sel("addresses"));
369
561
  if (!boxes.length) return;
370
- showGlobal(root, { "addresses-loading": true, "addresses-empty": false });
562
+ showIn(root, "show", { "addresses-loading": true, "addresses-empty": false });
371
563
  let list;
372
564
  try {
373
- list = addressCache = await addresses();
374
- } catch (err) {
375
- reportError(err, "addresses");
376
- showGlobal(root, { "addresses-loading": false, "addresses-error": true });
565
+ list = await addresses();
566
+ } catch (error) {
567
+ reportError(error, "addresses");
568
+ showIn(root, "show", { "addresses-loading": false, "addresses-error": true });
377
569
  return;
378
570
  }
379
- showGlobal(root, { "addresses-loading": false, "addresses-empty": list.length === 0, "addresses-error": false });
380
- boxes.forEach((box) => repeat(box, list, (row, a) => {
381
- row.dataset.tetherAddress = a.id;
382
- qsa(row, sel("address-bind")).concat(row.matches(sel("address-bind")) ? [row] : []).forEach((b) => {
383
- 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")];
384
- if (v != null) setText(b, v);
385
- });
386
- showIn(row, "address-show", { default: a.isDefault, "not-default": !a.isDefault });
387
- }));
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
+ });
388
576
  }
389
- var SUB_ACTIONS = ["pause", "resume", "skip", "unskip", "cancel"];
390
- function subConds(c) {
391
- const next = c.upcomingBillingCycles?.nodes?.[0];
392
- 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";
393
583
  return {
394
- active: st === "ACTIVE",
395
- paused: st === "PAUSED",
396
- cancelled: st === "CANCELLED",
397
- expired: st === "EXPIRED",
398
- failed: st === "FAILED",
584
+ active,
585
+ paused: status === "PAUSED",
586
+ cancelled: status === "CANCELLED",
587
+ expired: status === "EXPIRED",
588
+ failed: status === "FAILED",
399
589
  skipped: Boolean(next?.skipped),
400
- "can-pause": st === "ACTIVE",
401
- "can-resume": st === "PAUSED" || st === "FAILED",
402
- "can-skip": st === "ACTIVE" && Boolean(next) && !next.skipped,
403
- "can-unskip": st === "ACTIVE" && Boolean(next?.skipped),
404
- "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"
405
595
  };
406
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)
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
+ });
650
+ }
407
651
  async function renderSubscriptions(root) {
408
652
  const boxes = qsa(root, sel("subscriptions"));
409
653
  if (!boxes.length) return;
410
- showGlobal(root, { "subscriptions-loading": true, "subscriptions-empty": false });
654
+ showIn(root, "show", { "subscriptions-loading": true, "subscriptions-empty": false });
411
655
  let list;
412
656
  try {
413
657
  list = await subscriptions();
414
- } catch (err) {
415
- reportError(err, "subscriptions");
416
- showGlobal(root, { "subscriptions-loading": false, "subscriptions-error": true });
658
+ } catch (error) {
659
+ reportError(error, "subscriptions");
660
+ showIn(root, "show", { "subscriptions-loading": false, "subscriptions-error": true });
417
661
  return;
418
662
  }
419
- showGlobal(root, { "subscriptions-loading": false, "subscriptions-empty": list.length === 0, "subscriptions-error": false });
420
- boxes.forEach((box) => repeat(box, list, (row, c) => {
421
- row.dataset.tetherSubscription = c.id;
422
- row.setAttribute(attr("subscription-status"), lower(c.status));
423
- const ls = c.lines?.nodes || [];
424
- const n = c.deliveryPolicy?.intervalCount?.count || 1;
425
- const unit = lower(c.deliveryPolicy?.interval);
426
- const total = ls.reduce((sum, l) => sum + parseFloat(l.lineDiscountedPrice?.amount || 0), 0);
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
- }));
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
+ });
459
671
  }
460
- async function renderPages(root = document) {
461
- if (!bound) {
462
- bound = true;
463
- 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;
464
688
  }
465
- await Promise.all([
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
- ]);
689
+ return fields;
471
690
  }
472
- 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]));
473
- async function act(el, fn, { error } = {}) {
474
- if (el.getAttribute("aria-busy") === "true") return void 0;
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: /, "");
697
+ }
698
+ async function act(el, change) {
699
+ if (el.getAttribute("aria-busy") === "true") return "busy";
475
700
  el.classList.add("is-busy");
476
701
  el.setAttribute("aria-busy", "true");
477
702
  el.setAttribute(attr("form-state"), "pending");
478
- 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
+ });
479
707
  try {
480
- const out = await fn();
708
+ await change();
481
709
  el.setAttribute(attr("form-state"), "saved");
482
- return out;
483
- } catch (err) {
710
+ return "saved";
711
+ } catch (error) {
484
712
  el.setAttribute(attr("form-state"), "error");
485
- const msg = err?.userErrors?.map((u) => u.message).join(" ") || err?.message || "Something went wrong";
486
- qsa(el, sel("form-error")).forEach((e) => setText(e, msg.replace(/^Customer accounts: /, "")));
487
- if (error) reportError(err, error);
488
- return void 0;
713
+ errorBoxes.forEach((box) => {
714
+ setText(box, messageOf(error));
715
+ });
716
+ return "error";
489
717
  } finally {
490
718
  el.classList.remove("is-busy");
491
719
  el.removeAttribute("aria-busy");
492
720
  }
493
721
  }
494
- function bindPages() {
495
- document.addEventListener("submit", (e) => {
496
- const f = e.target;
497
- if (f.matches?.(sel("profile-form"))) {
498
- e.preventDefault();
499
- act(f, async () => {
500
- await updateProfile(fieldsOf(f));
501
- await ctx.bindCustomer?.(document);
502
- });
503
- } else if (f.matches?.(sel("address-form"))) {
504
- e.preventDefault();
505
- const id = f.dataset.tetherAddressId || void 0;
506
- const isDefault = Boolean(f.elements?.isDefault?.checked);
507
- act(f, async () => {
508
- await saveAddress(fieldsOf(f), { id, isDefault });
509
- f.reset();
510
- delete f.dataset.tetherAddressId;
511
- await renderAddresses(document);
512
- });
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 : "";
513
766
  }
514
- }, true);
515
- document.addEventListener("input", (e) => {
516
- if (e.target.closest?.(sel("profile-form"))) e.target.dataset.tetherTouched = "1";
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
+ });
517
816
  });
518
- document.addEventListener("click", (e) => {
519
- const t = e.target;
520
- const row = t.closest?.("[data-tether-address]");
521
- const confirmOk = (btn2) => {
522
- const q = get(btn2, "confirm");
523
- return !q || window.confirm(q);
524
- };
525
- let btn;
526
- if ((btn = t.closest?.(sel("address-delete"))) && row) {
527
- e.preventDefault();
528
- if (confirmOk(btn)) act(row, async () => {
529
- await deleteAddress(row.dataset.tetherAddress);
530
- await renderAddresses(document);
531
- });
532
- } else if ((btn = t.closest?.(sel("address-default"))) && row) {
533
- e.preventDefault();
534
- act(row, async () => {
535
- await saveAddress(null, { id: row.dataset.tetherAddress, isDefault: true });
536
- await renderAddresses(document);
537
- });
538
- } else if ((btn = t.closest?.(sel("address-edit"))) && row) {
539
- e.preventDefault();
540
- const a = (addressCache || []).find((x) => x.id === row.dataset.tetherAddress);
541
- const f = document.querySelector(sel("address-form"));
542
- if (a && f) {
543
- f.dataset.tetherAddressId = a.id;
544
- [...f.elements].forEach((i) => {
545
- if (i.name && i.name in a) i.value = a[i.name] ?? "";
546
- if (i.name === "isDefault") i.checked = a.isDefault;
547
- });
548
- f.scrollIntoView?.({ block: "nearest" });
549
- }
550
- } else if (btn = t.closest?.(sel("address-new"))) {
551
- const f = document.querySelector(sel("address-form"));
552
- if (f) {
553
- f.reset();
554
- delete f.dataset.tetherAddressId;
555
- }
556
- } else if (btn = t.closest?.(sel("subscription-action"))) {
557
- e.preventDefault();
558
- const sub = btn.closest("[data-tether-subscription]");
559
- const a = get(btn, "subscription-action");
560
- if (!sub || !SUB_ACTIONS.includes(a) || btn.disabled || !confirmOk(btn)) return;
561
- const id = sub.dataset.tetherSubscription;
562
- sub.setAttribute(attr("subscription-state"), "pending");
563
- act(sub, async () => {
564
- await subscriptionAction(id, a);
565
- await renderSubscriptions(document);
566
- }).then(() => {
567
- const state = sub.getAttribute(attr("form-state")) === "error" ? "error" : "done";
568
- qsa(document, "[data-tether-subscription]").filter((r) => r === sub || r.dataset.tetherSubscription === id).forEach((r) => r.setAttribute(attr("subscription-state"), state));
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
- });
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);
841
+ });
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";
586
865
  }
587
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
+ });
588
914
  }
589
915
 
590
916
  // src/parts/account-pages.js
591
- 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;
592
923
  })();