@tapcart/mobile-components 0.16.1 → 0.16.2

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.
@@ -9,6 +9,29 @@ type UseOrderDetailsProps = {
9
9
  type UseProductsReturn = {
10
10
  orderDetails: Record<string, any>;
11
11
  };
12
+ /**
13
+ * Effective (post-edit) quantity for an order line item, correct across BOTH
14
+ * Shopify order APIs the app consumes:
15
+ *
16
+ * - Storefront API exposes `currentQuantity` (ordered minus removed); it is 0
17
+ * for a line removed via Order Editing. Authoritative when present.
18
+ * - New Customer Account API has NO `currentQuantity`. There the only
19
+ * per-line signal is `refundableQuantity` (= quantity − refunded), which is
20
+ * also driven down to the post-edit count by an Order Editing removal
21
+ * (verified against real prod data: a removed line has refundableQuantity 0
22
+ * with no refund record). We trust it ONLY when the order was `edited` AND
23
+ * has no refund activity — because a refund/return ALSO lowers
24
+ * `refundableQuantity`, and `edited` is sticky, so on an edited-then-refunded
25
+ * order we cannot tell an edit-removal from a return. In that case we fall
26
+ * back to the ordered `quantity` (show the item) rather than risk hiding a
27
+ * line the customer actually bought / returned, or blanking a fully-refunded
28
+ * order. Trade-off: an item removed via an edit that DID issue a refund is
29
+ * not hidden (needs a per-line signal the API doesn't expose).
30
+ *
31
+ * Exported so blocks (PurchaseOverview, OrderHistory, OrderStatus) that build
32
+ * their own order objects from raw `customer.orders` share one implementation.
33
+ */
34
+ export declare const getEffectiveLineQuantity: (order: Record<string, any>, lineItem: Record<string, any>) => number;
12
35
  export declare const transformOrderDetails: (order: Record<string, any>) => {
13
36
  orderDetails: Record<string, any>;
14
37
  checkoutData: Record<string, any>;
@@ -1 +1 @@
1
- {"version":3,"file":"use-order-details.d.ts","sourceRoot":"","sources":["../../../components/hooks/use-order-details.ts"],"names":[],"mappings":"AAKA,KAAK,oBAAoB,GAAG;IAC1B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,OAAO,CAAA;CACf,CAAA;AAED,KAAK,iBAAiB,GAAG;IACvB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CAClC,CAAA;AA0LD,eAAO,MAAM,qBAAqB,UACzB,OAAO,MAAM,EAAE,GAAG,CAAC;kBACT,OAAO,MAAM,EAAE,GAAG,CAAC;kBAAgB,OAAO,MAAM,EAAE,GAAG,CAAC;CAmOxE,CAAA;AAED,wBAAgB,eAAe,CAAC,EAC9B,SAAS,EACT,MAAM,EACN,KAAK,EACL,QAAQ,EACR,OAAO,EACP,IAAY,GACb,EAAE,oBAAoB,GAAG,iBAAiB,CAiE1C"}
1
+ {"version":3,"file":"use-order-details.d.ts","sourceRoot":"","sources":["../../../components/hooks/use-order-details.ts"],"names":[],"mappings":"AAKA,KAAK,oBAAoB,GAAG;IAC1B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,OAAO,CAAA;CACf,CAAA;AAED,KAAK,iBAAiB,GAAG;IACvB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CAClC,CAAA;AAwMD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,wBAAwB,UAC5B,OAAO,MAAM,EAAE,GAAG,CAAC,YAChB,OAAO,MAAM,EAAE,GAAG,CAAC,KAC5B,MAUF,CAAA;AAED,eAAO,MAAM,qBAAqB,UACzB,OAAO,MAAM,EAAE,GAAG,CAAC;kBACT,OAAO,MAAM,EAAE,GAAG,CAAC;kBAAgB,OAAO,MAAM,EAAE,GAAG,CAAC;CAoOxE,CAAA;AAED,wBAAgB,eAAe,CAAC,EAC9B,SAAS,EACT,MAAM,EACN,KAAK,EACL,QAAQ,EACR,OAAO,EACP,IAAY,GACb,EAAE,oBAAoB,GAAG,iBAAiB,CAiE1C"}
@@ -138,6 +138,54 @@ const updateLineDetails = (line, product) => {
138
138
  line.sellingPlan = (_k = (_j = product.sellingPlanAllocation) === null || _j === void 0 ? void 0 : _j.sellingPlan) === null || _k === void 0 ? void 0 : _k.name;
139
139
  line.variantName = (_l = product.variant) === null || _l === void 0 ? void 0 : _l.title;
140
140
  };
141
+ /**
142
+ * True when an order has any refund/return activity. Used to keep the
143
+ * Customer-Account-API `refundableQuantity` heuristic (below) away from orders
144
+ * whose `refundableQuantity` was lowered by a refund rather than an order edit.
145
+ */
146
+ const hasRefundActivity = (order) => {
147
+ var _a, _b, _c;
148
+ if (Array.isArray(order === null || order === void 0 ? void 0 : order.refunds) && order.refunds.length > 0)
149
+ return true;
150
+ const refunded = (_c = (_b = (_a = order === null || order === void 0 ? void 0 : order.totalRefunded) === null || _a === void 0 ? void 0 : _a.amount) !== null && _b !== void 0 ? _b : order === null || order === void 0 ? void 0 : order.totalRefunded) !== null && _c !== void 0 ? _c : order === null || order === void 0 ? void 0 : order.totalRefund;
151
+ if (refunded != null && parseFloat(String(refunded)) > 0)
152
+ return true;
153
+ const status = String((order === null || order === void 0 ? void 0 : order.financialStatus) || "").toUpperCase();
154
+ return status.includes("REFUND"); // REFUNDED / PARTIALLY_REFUNDED
155
+ };
156
+ /**
157
+ * Effective (post-edit) quantity for an order line item, correct across BOTH
158
+ * Shopify order APIs the app consumes:
159
+ *
160
+ * - Storefront API exposes `currentQuantity` (ordered minus removed); it is 0
161
+ * for a line removed via Order Editing. Authoritative when present.
162
+ * - New Customer Account API has NO `currentQuantity`. There the only
163
+ * per-line signal is `refundableQuantity` (= quantity − refunded), which is
164
+ * also driven down to the post-edit count by an Order Editing removal
165
+ * (verified against real prod data: a removed line has refundableQuantity 0
166
+ * with no refund record). We trust it ONLY when the order was `edited` AND
167
+ * has no refund activity — because a refund/return ALSO lowers
168
+ * `refundableQuantity`, and `edited` is sticky, so on an edited-then-refunded
169
+ * order we cannot tell an edit-removal from a return. In that case we fall
170
+ * back to the ordered `quantity` (show the item) rather than risk hiding a
171
+ * line the customer actually bought / returned, or blanking a fully-refunded
172
+ * order. Trade-off: an item removed via an edit that DID issue a refund is
173
+ * not hidden (needs a per-line signal the API doesn't expose).
174
+ *
175
+ * Exported so blocks (PurchaseOverview, OrderHistory, OrderStatus) that build
176
+ * their own order objects from raw `customer.orders` share one implementation.
177
+ */
178
+ export const getEffectiveLineQuantity = (order, lineItem) => {
179
+ var _a;
180
+ if (lineItem.currentQuantity != null)
181
+ return lineItem.currentQuantity;
182
+ if ((order === null || order === void 0 ? void 0 : order.edited) === true &&
183
+ lineItem.refundableQuantity != null &&
184
+ !hasRefundActivity(order)) {
185
+ return lineItem.refundableQuantity;
186
+ }
187
+ return (_a = lineItem.quantity) !== null && _a !== void 0 ? _a : 1;
188
+ };
141
189
  export const transformOrderDetails = (order) => {
142
190
  var _a;
143
191
  // Helper function to safely parse amounts
@@ -148,12 +196,12 @@ export const transformOrderDetails = (order) => {
148
196
  return parseFloat(amount) || 0;
149
197
  return 0;
150
198
  };
151
- // Shopify Order Editing sets currentQuantity to 0 for removed/refunded
152
- // line items those must not be shown to the customer
153
- const activeLineItems = (order.lineItems || []).filter((lineItem) => { var _a, _b; return ((_b = (_a = lineItem.currentQuantity) !== null && _a !== void 0 ? _a : lineItem.quantity) !== null && _b !== void 0 ? _b : 1) > 0; });
199
+ const effectiveQuantity = (lineItem) => getEffectiveLineQuantity(order, lineItem);
200
+ // Line items removed via Order Editing must not be shown to the customer
201
+ const activeLineItems = (order.lineItems || []).filter((lineItem) => effectiveQuantity(lineItem) > 0);
154
202
  // Transform line items to cart lines
155
203
  const cartLines = activeLineItems.map((lineItem) => {
156
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
204
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
157
205
  const variant = lineItem.variant || {};
158
206
  const product = variant.product || {};
159
207
  return {
@@ -188,13 +236,13 @@ export const transformOrderDetails = (order) => {
188
236
  productId: ((_k = variant.product) === null || _k === void 0 ? void 0 : _k.id) || lineItem.productId,
189
237
  merchandiseId: variant.id || lineItem.merchandiseId,
190
238
  title: lineItem.title || product.title || "Unknown Product",
191
- quantity: (_m = (_l = lineItem.currentQuantity) !== null && _l !== void 0 ? _l : lineItem.quantity) !== null && _m !== void 0 ? _m : 1,
239
+ quantity: effectiveQuantity(lineItem),
192
240
  uniqueId: crypto.randomUUID(),
193
241
  vendor: product.vendor || lineItem.vendor || "Unknown",
194
242
  compareAtPrice: {
195
- amount: parseAmount(((_o = lineItem.originalTotalPrice) === null || _o === void 0 ? void 0 : _o.amount) || ((_p = lineItem.compareAtPrice) === null || _p === void 0 ? void 0 : _p.amount)),
196
- currencyCode: ((_q = lineItem.originalTotalPrice) === null || _q === void 0 ? void 0 : _q.currencyCode) ||
197
- ((_r = lineItem.compareAtPrice) === null || _r === void 0 ? void 0 : _r.currencyCode) ||
243
+ amount: parseAmount(((_l = lineItem.originalTotalPrice) === null || _l === void 0 ? void 0 : _l.amount) || ((_m = lineItem.compareAtPrice) === null || _m === void 0 ? void 0 : _m.amount)),
244
+ currencyCode: ((_o = lineItem.originalTotalPrice) === null || _o === void 0 ? void 0 : _o.currencyCode) ||
245
+ ((_p = lineItem.compareAtPrice) === null || _p === void 0 ? void 0 : _p.currencyCode) ||
198
246
  order.currency ||
199
247
  "USD",
200
248
  },
@@ -265,7 +313,7 @@ export const transformOrderDetails = (order) => {
265
313
  })),
266
314
  subtotalPrice: wrapMoney(subtotal, currencyCode),
267
315
  lineItems: activeLineItems.map((lineItem) => {
268
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
316
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
269
317
  const variant = lineItem.variant || {};
270
318
  const product = variant.product || {};
271
319
  const currencyCode = ((_a = lineItem.discountedTotalPrice) === null || _a === void 0 ? void 0 : _a.currencyCode) ||
@@ -315,9 +363,9 @@ export const transformOrderDetails = (order) => {
315
363
  discountApplication: allocation.discountApplication || {},
316
364
  });
317
365
  }),
318
- quantity: (_t = (_s = lineItem.currentQuantity) !== null && _s !== void 0 ? _s : lineItem.quantity) !== null && _t !== void 0 ? _t : 1,
366
+ quantity: effectiveQuantity(lineItem),
319
367
  title: lineItem.title || product.title,
320
- id: ((_u = variant.id) === null || _u === void 0 ? void 0 : _u.split("/").pop()) || ((_v = lineItem.variantId) === null || _v === void 0 ? void 0 : _v.split("/").pop()),
368
+ id: ((_s = variant.id) === null || _s === void 0 ? void 0 : _s.split("/").pop()) || ((_t = lineItem.variantId) === null || _t === void 0 ? void 0 : _t.split("/").pop()),
321
369
  };
322
370
  }),
323
371
  totalPrice: wrapMoney(total, currencyCode),
@@ -33,11 +33,12 @@ declare const DrawerContentBase: React.ForwardRefExoticComponent<Omit<React.Deta
33
33
  containerRef?: HTMLElement | undefined;
34
34
  maxHeight?: string | undefined;
35
35
  } & React.RefAttributes<HTMLDivElement>>;
36
+ declare const DrawerTitle: React.ForwardRefExoticComponent<Omit<import("@radix-ui/react-dialog").DialogTitleProps & React.RefAttributes<HTMLHeadingElement>, "ref"> & React.RefAttributes<HTMLHeadingElement>>;
36
37
  declare const DrawerFooter: {
37
38
  ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>): import("react/jsx-runtime").JSX.Element;
38
39
  displayName: string;
39
40
  };
40
- declare const DrawerDescription: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>, "ref"> & React.RefAttributes<HTMLParagraphElement>>;
41
+ declare const DrawerDescription: React.ForwardRefExoticComponent<Omit<import("@radix-ui/react-dialog").DialogDescriptionProps & React.RefAttributes<HTMLParagraphElement>, "ref"> & React.RefAttributes<HTMLParagraphElement>>;
41
42
  type DrawerHeaderProps = {
42
43
  iconLeftName?: string;
43
44
  iconRightName?: string;
@@ -46,5 +47,5 @@ type DrawerHeaderProps = {
46
47
  };
47
48
  declare const DrawerHeader: ({ title, iconLeftName, iconRightName, onCloseClick, }: DrawerHeaderProps) => import("react/jsx-runtime").JSX.Element;
48
49
  declare const DrawerContent: ({ children, className, ...props }: React.HTMLAttributes<HTMLDivElement>) => import("react/jsx-runtime").JSX.Element;
49
- export { Drawer, DrawerPortal, DrawerOverlay, DrawerTrigger, DrawerClose, DrawerContentBase, DrawerContent, DrawerFooter, DrawerDescription, DrawerHeader, };
50
+ export { Drawer, DrawerPortal, DrawerOverlay, DrawerTrigger, DrawerClose, DrawerContentBase, DrawerContent, DrawerFooter, DrawerTitle, DrawerDescription, DrawerHeader, };
50
51
  //# sourceMappingURL=drawer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"drawer.d.ts","sourceRoot":"","sources":["../../../components/ui/drawer.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,MAAM,IAAI,eAAe,EAAE,MAAM,MAAM,CAAA;AAKhD,KAAK,kBAAkB,GAAG,KAAK,CAAC,wBAAwB,CAAC,QAAQ,CAAC,GAAG;IACnE,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,CAAA;AAED,KAAK,iBAAiB,GAAG;IACvB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,YAAY,CAAC,EAAE,WAAW,CAAA;CAC3B,CAAA;AAED,KAAK,gBAAgB,GAAG,KAAK,CAAC,wBAAwB,CAAC,QAAQ,CAAC,GAAG;IACjE,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,CAAA;AAED,QAAA,MAAM,aAAa,8BAA0D,CAAA;AAG7E,QAAA,MAAM,YAAY;iCAAgC,iBAAiB;;CAgBlE,CAAA;AAGD,QAAA,MAAM,WAAW,4BAAsD,CAAA;AAGvE,KAAK,WAAW,GAAG,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,IAAI,CAAC,GAAG;IACrE,YAAY,CAAC,EAAE,WAAW,CAAA;CAC3B,CAAA;AAED,QAAA,MAAM,MAAM;0CAAyC,WAAW;;CAS/D,CAAA;AAOD,QAAA,MAAM,aAAa;;wCAYlB,CAAA;AAWD,QAAA,MAAM,iBAAiB;;;;;;wCA2CtB,CAAA;AA0BD,QAAA,MAAM,YAAY;8BAGf,MAAM,cAAc,CAAC,cAAc,CAAC;;CAQtC,CAAA;AAGD,QAAA,MAAM,iBAAiB,qLASrB,CAAA;AAGF,KAAK,iBAAiB,GAAG;IACvB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,KAAK,EAAE,MAAM,CAAA;IACb,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,UAAU,KAAK,IAAI,CAAA;CACjD,CAAA;AAED,QAAA,MAAM,YAAY,0DAKf,iBAAiB,4CA8BnB,CAAA;AAED,QAAA,MAAM,aAAa,sCAIhB,MAAM,cAAc,CAAC,cAAc,CAAC,4CAMtC,CAAA;AAED,OAAO,EACL,MAAM,EACN,YAAY,EACZ,aAAa,EACb,aAAa,EACb,WAAW,EACX,iBAAiB,EACjB,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,YAAY,GACb,CAAA"}
1
+ {"version":3,"file":"drawer.d.ts","sourceRoot":"","sources":["../../../components/ui/drawer.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,MAAM,IAAI,eAAe,EAAE,MAAM,MAAM,CAAA;AAKhD,KAAK,kBAAkB,GAAG,KAAK,CAAC,wBAAwB,CAAC,QAAQ,CAAC,GAAG;IACnE,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,CAAA;AAED,KAAK,iBAAiB,GAAG;IACvB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,YAAY,CAAC,EAAE,WAAW,CAAA;CAC3B,CAAA;AAED,KAAK,gBAAgB,GAAG,KAAK,CAAC,wBAAwB,CAAC,QAAQ,CAAC,GAAG;IACjE,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,CAAA;AAED,QAAA,MAAM,aAAa,8BAA0D,CAAA;AAG7E,QAAA,MAAM,YAAY;iCAAgC,iBAAiB;;CAgBlE,CAAA;AAGD,QAAA,MAAM,WAAW,4BAAsD,CAAA;AAGvE,KAAK,WAAW,GAAG,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,IAAI,CAAC,GAAG;IACrE,YAAY,CAAC,EAAE,WAAW,CAAA;CAC3B,CAAA;AAED,QAAA,MAAM,MAAM;0CAAyC,WAAW;;CAS/D,CAAA;AAOD,QAAA,MAAM,aAAa;;wCAYlB,CAAA;AAWD,QAAA,MAAM,iBAAiB;;;;;;wCA2CtB,CAAA;AAWD,QAAA,MAAM,WAAW,qLAYf,CAAA;AAGF,QAAA,MAAM,YAAY;8BAGf,MAAM,cAAc,CAAC,cAAc,CAAC;;CAQtC,CAAA;AAGD,QAAA,MAAM,iBAAiB,+LASrB,CAAA;AAGF,KAAK,iBAAiB,GAAG;IACvB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,KAAK,EAAE,MAAM,CAAA;IACb,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,UAAU,KAAK,IAAI,CAAA;CACjD,CAAA;AAED,QAAA,MAAM,YAAY,0DAKf,iBAAiB,4CA8BnB,CAAA;AAED,QAAA,MAAM,aAAa,sCAIhB,MAAM,cAAc,CAAC,cAAc,CAAC,4CAMtC,CAAA;AAED,OAAO,EACL,MAAM,EACN,YAAY,EACZ,aAAa,EACb,aAAa,EACb,WAAW,EACX,iBAAiB,EACjB,aAAa,EACb,YAAY,EACZ,WAAW,EACX,iBAAiB,EACjB,YAAY,GACb,CAAA"}
@@ -71,9 +71,9 @@ const DrawerFooter = (_a) => {
71
71
  DrawerFooter.displayName = "DrawerFooter";
72
72
  const DrawerDescription = React.forwardRef((_a, ref) => {
73
73
  var { className } = _a, props = __rest(_a, ["className"]);
74
- return (_jsx("p", Object.assign({ ref: ref, className: cn("text-sm text-muted-foreground", className) }, props)));
74
+ return (_jsx(DrawerPrimitive.Description, Object.assign({ ref: ref, className: cn("text-sm text-muted-foreground", className) }, props)));
75
75
  });
76
- DrawerDescription.displayName = "DrawerDescription";
76
+ DrawerDescription.displayName = DrawerPrimitive.Description.displayName;
77
77
  const DrawerHeader = ({ title, iconLeftName, iconRightName, onCloseClick, }) => {
78
78
  return (_jsxs(DrawerHeaderBase, Object.assign({ className: "p-4 text-center flex justify-between" }, { children: [iconLeftName ? (_jsx(DrawerClose, Object.assign({ className: "h-6 w-6 p-0", onClick: onCloseClick }, { children: _jsx(Icon, { name: iconLeftName, color: "coreColors-secondaryIcon", className: "h-6 w-6 p-0", size: "md" }) }))) : (_jsx("div", { className: "w-6" })), _jsx(DrawerTitle, { children: title }), iconRightName ? (_jsx(DrawerClose, Object.assign({ className: "h-6 w-6 p-0", onClick: onCloseClick }, { children: _jsx(Icon, { name: iconRightName, color: "coreColors-secondaryIcon", className: "h-6 w-6 p-0", size: "md" }) }))) : (_jsx("div", { className: "w-6" }))] })));
79
79
  };
@@ -81,4 +81,4 @@ const DrawerContent = (_a) => {
81
81
  var { children, className } = _a, props = __rest(_a, ["children", "className"]);
82
82
  return (_jsx("div", Object.assign({ className: cn("h-full overflow-scroll", className) }, props, { children: children })));
83
83
  };
84
- export { Drawer, DrawerPortal, DrawerOverlay, DrawerTrigger, DrawerClose, DrawerContentBase, DrawerContent, DrawerFooter, DrawerDescription, DrawerHeader, };
84
+ export { Drawer, DrawerPortal, DrawerOverlay, DrawerTrigger, DrawerClose, DrawerContentBase, DrawerContent, DrawerFooter, DrawerTitle, DrawerDescription, DrawerHeader, };
@@ -1,4 +1,4 @@
1
- import { transformOrderDetails } from "../components/hooks/use-order-details";
1
+ import { transformOrderDetails, getEffectiveLineQuantity, } from "../components/hooks/use-order-details";
2
2
  // jsdom does not implement crypto.randomUUID, which transformOrderDetails
3
3
  // uses for line uniqueIds
4
4
  beforeAll(() => {
@@ -63,3 +63,86 @@ describe("transformOrderDetails — Shopify Order Editing (currentQuantity)", ()
63
63
  expect(orderDetails.cart.lines[0].quantity).toBe(1);
64
64
  });
65
65
  });
66
+ describe("transformOrderDetails — New Customer Account API (no currentQuantity)", () => {
67
+ // Modeled on real prod data (Pink Palm Puff order #PPP95701331): the
68
+ // Customer Account API LineItem has NO `currentQuantity` — a line removed via
69
+ // Order Editing keeps `quantity: 1` and signals removal only via
70
+ // `refundableQuantity: 0`. The kept line has `refundableQuantity: 1`.
71
+ const editedOrder = {
72
+ id: "gid://shopify/Order/10929524212006",
73
+ currency: "USD",
74
+ edited: true,
75
+ financialStatus: "PAID",
76
+ refunds: [],
77
+ totalRefunded: { amount: "0.0", currencyCode: "USD" },
78
+ totalAmount: "63.88",
79
+ lineItems: [
80
+ {
81
+ title: "Couture Carryall in Blush Bay (Reversible)",
82
+ quantity: 1,
83
+ refundableQuantity: 0,
84
+ price: { amount: "99.0", currencyCode: "USD" },
85
+ },
86
+ {
87
+ title: "Malibu Slippers in Blush Bay",
88
+ quantity: 1,
89
+ refundableQuantity: 1,
90
+ price: { amount: "59.0", currencyCode: "USD" },
91
+ },
92
+ ],
93
+ };
94
+ it("hides items removed via order editing on an edited order", () => {
95
+ const { orderDetails, checkoutData } = transformOrderDetails(editedOrder);
96
+ expect(orderDetails.cart.lines).toHaveLength(1);
97
+ expect(orderDetails.cart.lines[0].title).toBe("Malibu Slippers in Blush Bay");
98
+ expect(checkoutData.lineItems).toHaveLength(1);
99
+ expect(checkoutData.lineItems[0].title).toBe("Malibu Slippers in Blush Bay");
100
+ });
101
+ it("does NOT hide items on an UN-edited fully-refunded order", () => {
102
+ // Real prod data: cancelled+refunded order #PPP95700931 — edited:false,
103
+ // both lines refundableQuantity:0. These must still display in full.
104
+ const refundedOrder = Object.assign(Object.assign({}, editedOrder), { id: "gid://shopify/Order/10929514119462", edited: false, lineItems: editedOrder.lineItems.map((li) => (Object.assign(Object.assign({}, li), { refundableQuantity: 0 }))) });
105
+ const { orderDetails } = transformOrderDetails(refundedOrder);
106
+ expect(orderDetails.cart.lines).toHaveLength(2);
107
+ });
108
+ it("does NOT hide items on an EDITED order that also has a refund/return", () => {
109
+ // `edited` is sticky in Shopify and `refundableQuantity` drops on refunds
110
+ // too, so an edited-then-returned order must NOT collapse: fall back to
111
+ // ordered quantity rather than blank the order / hide bought items.
112
+ const editedAndRefunded = Object.assign(Object.assign({}, editedOrder), { financialStatus: "REFUNDED", totalRefunded: { amount: "171.06", currencyCode: "USD" }, refunds: [{ id: "gid://shopify/Refund/1", createdAt: "2026-07-08" }], lineItems: editedOrder.lineItems.map((li) => (Object.assign(Object.assign({}, li), { refundableQuantity: 0 }))) });
113
+ const { orderDetails } = transformOrderDetails(editedAndRefunded);
114
+ expect(orderDetails.cart.lines).toHaveLength(2);
115
+ });
116
+ it("reduces (not hides) a quantity edited down on an edited order", () => {
117
+ const { orderDetails } = transformOrderDetails(Object.assign(Object.assign({}, editedOrder), { lineItems: [
118
+ {
119
+ title: "Pink Palm Pajamas",
120
+ quantity: 3,
121
+ refundableQuantity: 2,
122
+ price: { amount: "95.0", currencyCode: "USD" },
123
+ },
124
+ ] }));
125
+ expect(orderDetails.cart.lines).toHaveLength(1);
126
+ expect(orderDetails.cart.lines[0].quantity).toBe(2);
127
+ });
128
+ });
129
+ describe("getEffectiveLineQuantity", () => {
130
+ it("prefers currentQuantity when present (Storefront API)", () => {
131
+ expect(getEffectiveLineQuantity({ edited: true }, { currentQuantity: 0, quantity: 1, refundableQuantity: 1 })).toBe(0);
132
+ });
133
+ it("uses refundableQuantity on edited orders without currentQuantity", () => {
134
+ expect(getEffectiveLineQuantity({ edited: true }, { quantity: 1, refundableQuantity: 0 })).toBe(0);
135
+ });
136
+ it("uses quantity on un-edited orders even when refundableQuantity differs", () => {
137
+ expect(getEffectiveLineQuantity({ edited: false }, { quantity: 3, refundableQuantity: 0 })).toBe(3);
138
+ });
139
+ it("ignores refundableQuantity on an edited order with a refund (refunds array)", () => {
140
+ expect(getEffectiveLineQuantity({ edited: true, refunds: [{ id: "r1" }] }, { quantity: 1, refundableQuantity: 0 })).toBe(1);
141
+ });
142
+ it("ignores refundableQuantity on an edited order with a refund (financialStatus)", () => {
143
+ expect(getEffectiveLineQuantity({ edited: true, financialStatus: "PARTIALLY_REFUNDED" }, { quantity: 3, refundableQuantity: 1 })).toBe(3);
144
+ });
145
+ it("ignores refundableQuantity on an edited order with totalRefunded > 0", () => {
146
+ expect(getEffectiveLineQuantity({ edited: true, totalRefunded: { amount: "50.0" } }, { quantity: 2, refundableQuantity: 0 })).toBe(2);
147
+ });
148
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tapcart/mobile-components",
3
- "version": "0.16.1",
3
+ "version": "0.16.2",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "style": "dist/styles.css",