@snowcone-app/ui 0.8.3 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.9.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#2936](https://github.com/snowcone-app/snowcone-monorepo/pull/2936) [`3c37e27`](https://github.com/snowcone-app/snowcone-monorepo/commit/3c37e27da40c8865b4c4bd71ec9454ec7e64bc4c) Thanks [@kevinsproles](https://github.com/kevinsproles)! - `AddToCart` waits for your add and never reports a failure as success. An async `onClick` is awaited: the button shows
8
+ "Added!" only after it resolves, and a rejection (or throw) shows `errorText` (new prop, default
9
+ "Couldn't add — try again"), announces the error's message in a `role="alert"`, calls `onError`, and leaves the button
10
+ enabled to retry. Previously `onClick` was called without awaiting after a fixed simulated delay, so a failed add still
11
+ said "Added!". The button exposes `data-add-to-cart="idle | adding | added | error"` (type `AddToCartStatus`) for tests.
12
+ `simulateDelay` now applies only when there is no `onClick` (demos).
13
+
3
14
  ## 0.8.3
4
15
 
5
16
  ### Patch Changes
package/dist/index.cjs CHANGED
@@ -4921,6 +4921,7 @@ function AddToCart({
4921
4921
  text = "Add to Bag",
4922
4922
  loadingText = "Adding...",
4923
4923
  successText = "Added!",
4924
+ errorText = "Couldn't add \u2014 try again",
4924
4925
  disabled = false,
4925
4926
  className = "",
4926
4927
  quantity = 1,
@@ -4930,8 +4931,10 @@ function AddToCart({
4930
4931
  }) {
4931
4932
  const context = useProduct();
4932
4933
  const shopContext = useShopOptional();
4933
- const [loading, setLoading] = (0, import_react15.useState)(false);
4934
- const [success, setSuccess] = (0, import_react15.useState)(false);
4934
+ const [status, setStatus] = (0, import_react15.useState)("idle");
4935
+ const [errorMessage, setErrorMessage] = (0, import_react15.useState)(null);
4936
+ const loading = status === "adding";
4937
+ const success = status === "added";
4935
4938
  (0, import_react15.useEffect)(() => {
4936
4939
  checkProviders(
4937
4940
  "AddToCart",
@@ -4954,7 +4957,8 @@ function AddToCart({
4954
4957
  const handleClick = async () => {
4955
4958
  if (isDisabled || !product) return;
4956
4959
  try {
4957
- setLoading(true);
4960
+ setStatus("adding");
4961
+ setErrorMessage(null);
4958
4962
  const cartDetail = (0, import_sdk7.createCartDetail)({
4959
4963
  productId: product.id,
4960
4964
  quantity,
@@ -4965,20 +4969,23 @@ function AddToCart({
4965
4969
  if (!cartDetail) {
4966
4970
  throw new Error("Invalid selection - unable to create cart detail");
4967
4971
  }
4968
- await (0, import_sdk7.simulateCartOperation)(simulateDelay);
4969
- onClick?.(cartDetail);
4970
- setSuccess(true);
4972
+ if (onClick) {
4973
+ await onClick(cartDetail);
4974
+ } else {
4975
+ await (0, import_sdk7.simulateCartOperation)(simulateDelay);
4976
+ }
4977
+ setStatus("added");
4971
4978
  setTimeout(() => {
4972
- setSuccess(false);
4979
+ setStatus((s) => s === "added" ? "idle" : s);
4973
4980
  }, 2e3);
4974
4981
  } catch (error) {
4975
- onError?.(error);
4976
- console.error("Add to cart failed:", error);
4977
- } finally {
4978
- setLoading(false);
4982
+ const err = error instanceof Error ? error : new Error(String(error));
4983
+ setStatus("error");
4984
+ setErrorMessage(err.message);
4985
+ onError?.(err);
4979
4986
  }
4980
4987
  };
4981
- const buttonText = loading ? loadingText : success ? successText : text;
4988
+ const buttonText = loading ? loadingText : success ? successText : status === "error" ? errorText : text;
4982
4989
  const defaultStyles = "w-full bg-primary text-primary-foreground hover:bg-primary/90 px-6 py-3 rounded-button font-medium transition-colors";
4983
4990
  const buttonClasses = `
4984
4991
  ${defaultStyles}
@@ -4989,6 +4996,7 @@ function AddToCart({
4989
4996
  const getAriaLabel = () => {
4990
4997
  if (loading) return loadingText;
4991
4998
  if (success) return successText;
4999
+ if (status === "error") return `${errorText} - ${product?.name || "product"}`;
4992
5000
  if (!product) return text;
4993
5001
  return `${text} - ${product.name || "product"}`;
4994
5002
  };
@@ -5002,9 +5010,11 @@ function AddToCart({
5002
5010
  onClick: handleClick,
5003
5011
  "aria-label": getAriaLabel(),
5004
5012
  "aria-busy": loading,
5013
+ "data-add-to-cart": status,
5005
5014
  children: buttonText
5006
5015
  }
5007
- )
5016
+ ),
5017
+ status === "error" && errorMessage && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("p", { role: "alert", className: "mt-2 text-sm text-destructive", children: errorMessage })
5008
5018
  ] });
5009
5019
  }
5010
5020