@occluze/tether 0.6.7 → 0.7.0

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