fix stale prepaidOptions bug for update subscription

This commit is contained in:
Ayush Rodrigues
2025-12-02 19:21:40 +00:00
parent 48b48af344
commit 5293b0e3ad
7 changed files with 58 additions and 37 deletions

View File

@@ -132,7 +132,7 @@ export const AttachConfirmationInfo = ({
}
return (
<div className="space-y-2 px-4 pt-2">
<div className="space-y-2 px-4">
{infoBoxes.map((box, index) => (
<div key={index}>{box}</div>
))}

View File

@@ -134,17 +134,22 @@ export function AttachProductForm({
<div className="space-y-2">
<AttachProductSelection form={form} customerId={customerId} />
<AttachProductPrepaidOptions form={form} />
{entityId ? (
<InfoBox variant="info">
Attaching plan to entity{" "}
<span className="font-semibold">
{fullEntity?.name || fullEntity?.id}
</span>
</InfoBox>
<div className="pt-2">
<InfoBox variant="info">
Attaching plan to entity{" "}
<span className="font-semibold">
{fullEntity?.name || fullEntity?.id}
</span>
</InfoBox>
</div>
) : entities.length > 0 ? (
<InfoBox variant="info">
Attaching plan to customer - all entities will get access
</InfoBox>
<div className="pt-2">
<InfoBox variant="info">
Attaching plan to customer - all entities will get access
</InfoBox>
</div>
) : null}
</div>
</SheetSection>

View File

@@ -36,7 +36,7 @@ export function AttachProductPrepaidOptions({
}
return (
<div className="space-y-3 mt-4">
<div className="space-y-3 mt-4 mb-2">
<div className="space-y-2">
{prepaidItems.map((item) => {
const display = getFeaturePriceItemDisplay({

View File

@@ -1,6 +1,5 @@
import { isProductAlreadyEnabled } from "@autumn/shared";
import { PencilSimpleIcon } from "@phosphor-icons/react";
import { useEffect, useRef } from "react";
import { useNavigate } from "react-router";
import { IconButton } from "@/components/v2/buttons/IconButton";
import { useProductsQuery } from "@/hooks/queries/useProductsQuery";
@@ -8,7 +7,10 @@ import { useHasChanges } from "@/hooks/stores/useProductStore";
import { useEntity } from "@/hooks/stores/useSubscriptionStore";
import { pushPage } from "@/utils/genUtils";
import { useCusQuery } from "@/views/customers/customer/hooks/useCusQuery";
import type { UseAttachProductForm } from "./use-attach-product-form";
import {
type UseAttachProductForm,
useResetPrepaidOnProductChange,
} from "./use-attach-product-form";
interface AttachProductSelectionProps {
form: UseAttachProductForm;
@@ -26,25 +28,8 @@ export function AttachProductSelection({
const hasChanges = useHasChanges();
const { customer } = useCusQuery();
const { entityId } = useEntity();
const previousProductIdRef = useRef<string | undefined>();
useEffect(() => {
// Subscribe to form changes and clear prepaid options when productId changes
// Prevents stale prepaid options from causing "no prepaid price found" in the `checkout` call
const subscription = form.store.subscribe(() => {
const currentProductId = form.store.state.values.productId;
if (
previousProductIdRef.current !== undefined &&
previousProductIdRef.current !== currentProductId
) {
form.setFieldValue("prepaidOptions", {});
}
previousProductIdRef.current = currentProductId;
});
return () => subscription();
}, [form.store]);
useResetPrepaidOnProductChange({ form });
const handleCustomize = ({ productId }: { productId: string }) => {
if (!productId || !customerId) {

View File

@@ -17,8 +17,6 @@ export function AttachProductSummary({
);
}
console.log("previewData", previewData);
return (
<div className="text-sm">
<AttachConfirmationInfo previewData={previewData} />

View File

@@ -1,3 +1,4 @@
import { useEffect, useRef } from "react";
import { useAppForm } from "@/hooks/form/form";
import {
type AttachProductForm,
@@ -23,4 +24,30 @@ export function useAttachProductForm({
});
}
// Subscribe to form changes and clear prepaid options when productId changes
// Prevents stale prepaid options from causing "no prepaid price found" in the `checkout` call
export function useResetPrepaidOnProductChange({
form,
}: {
form: UseAttachProductForm;
}) {
const previousProductIdRef = useRef<string | undefined>();
useEffect(() => {
const subscription = form.store.subscribe(() => {
const currentProductId = form.store.state.values.productId;
if (
previousProductIdRef.current !== undefined &&
previousProductIdRef.current !== currentProductId
) {
form.setFieldValue("prepaidOptions", {});
}
previousProductIdRef.current = currentProductId;
});
return () => subscription();
}, [form.store, form.setFieldValue]);
}
export type UseAttachProductForm = ReturnType<typeof useAttachProductForm>;

View File

@@ -39,6 +39,8 @@ const FormContent = ({
const initialPrepaidOptions =
form.options.defaultValues?.prepaidOptions ?? {};
console.log("prepaidOptions", prepaidOptions);
const previewQuery = useAttachPreview({
customerId,
product,
@@ -109,7 +111,9 @@ function SheetContent({
}) {
const storeProduct = useProductStore((s) => s.product);
const product = storeProduct?.id ? storeProduct : (productV2 ?? undefined);
const { prepaidItems, isLoading } = usePrepaidItems({ product });
const { prepaidItems } = usePrepaidItems({ product });
console.log("prepaidItems", prepaidItems);
const subscriptionPrepaidValues = useMemo(
() =>
@@ -124,8 +128,8 @@ function SheetContent({
);
const initialPrepaidOptions = useMemo(() => {
if (isLoading || prepaidItems.length === 0) {
return subscriptionPrepaidValues;
if (prepaidItems.length === 0) {
return {};
}
return prepaidItems.reduce(
@@ -136,13 +140,15 @@ function SheetContent({
},
{} as Record<string, number | undefined>,
) as Record<string, number>;
}, [prepaidItems, subscriptionPrepaidValues, isLoading]);
}, [prepaidItems, subscriptionPrepaidValues]);
const form = useAttachProductForm({
initialProductId: cusProduct?.product.id ?? undefined,
initialPrepaidOptions,
});
console.log("initialPrepaidOptions", initialPrepaidOptions);
return (
<FormWrapper form={form}>
<div className="flex flex-col h-full">