mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-30 03:00:41 -04:00
fix(frontend): clear ?subscription=success URL param after showing toast
Replace toastShownRef guard with router.replace(pathname) so the success toast is not re-shown on page refresh and correctly re-fires on a second checkout in the same SPA session. Adds test coverage for the behaviour.
This commit is contained in:
@@ -10,12 +10,13 @@ import { SubscriptionTierSection } from "../SubscriptionTierSection";
|
||||
|
||||
// Mock next/navigation
|
||||
const mockSearchParams = new URLSearchParams();
|
||||
const mockRouterReplace = vi.fn();
|
||||
vi.mock("next/navigation", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("next/navigation")>();
|
||||
return {
|
||||
...actual,
|
||||
useSearchParams: () => mockSearchParams,
|
||||
useRouter: () => ({ push: vi.fn() }),
|
||||
useRouter: () => ({ push: vi.fn(), replace: mockRouterReplace }),
|
||||
usePathname: () => "/profile/credits",
|
||||
};
|
||||
});
|
||||
@@ -103,6 +104,7 @@ afterEach(() => {
|
||||
mockUseGetSubscriptionStatus.mockReset();
|
||||
mockUseUpdateSubscriptionTier.mockReset();
|
||||
mockToast.mockReset();
|
||||
mockRouterReplace.mockReset();
|
||||
// Reset search params
|
||||
mockSearchParams.delete("subscription");
|
||||
});
|
||||
@@ -289,4 +291,18 @@ describe("SubscriptionTierSection", () => {
|
||||
expect(screen.queryByText("Pro")).toBeNull();
|
||||
expect(screen.queryByText("Business")).toBeNull();
|
||||
});
|
||||
|
||||
it("shows success toast and clears URL param when ?subscription=success is present", async () => {
|
||||
mockSearchParams.set("subscription", "success");
|
||||
setupMocks();
|
||||
render(<SubscriptionTierSection />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockToast).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ title: "Subscription upgraded" }),
|
||||
);
|
||||
});
|
||||
// URL param must be stripped so a page refresh doesn't re-trigger the toast
|
||||
expect(mockRouterReplace).toHaveBeenCalledWith("/profile/credits");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
import { useEffect, useState } from "react";
|
||||
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
||||
import {
|
||||
useGetSubscriptionStatus,
|
||||
useUpdateSubscriptionTier,
|
||||
@@ -13,8 +13,9 @@ export type SubscriptionStatus = SubscriptionStatusResponse;
|
||||
export function useSubscriptionTierSection() {
|
||||
const searchParams = useSearchParams();
|
||||
const subscriptionStatus = searchParams.get("subscription");
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const { toast } = useToast();
|
||||
const toastShownRef = useRef(false);
|
||||
const [tierError, setTierError] = useState<string | null>(null);
|
||||
|
||||
const {
|
||||
@@ -36,22 +37,18 @@ export function useSubscriptionTierSection() {
|
||||
|
||||
useEffect(() => {
|
||||
if (subscriptionStatus === "success") {
|
||||
if (!toastShownRef.current) {
|
||||
toastShownRef.current = true;
|
||||
refetch();
|
||||
toast({
|
||||
title: "Subscription upgraded",
|
||||
description:
|
||||
"Your plan has been updated. It may take a moment to reflect.",
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Reset so the toast fires again if the user completes another checkout
|
||||
// during the same mount (e.g. SPA navigation away and back with a new
|
||||
// ?subscription=success param).
|
||||
toastShownRef.current = false;
|
||||
refetch();
|
||||
toast({
|
||||
title: "Subscription upgraded",
|
||||
description:
|
||||
"Your plan has been updated. It may take a moment to reflect.",
|
||||
});
|
||||
// Strip ?subscription=success from the URL so a page refresh does not
|
||||
// re-trigger the toast, and so a second checkout in the same session
|
||||
// correctly fires the toast again.
|
||||
router.replace(pathname);
|
||||
}
|
||||
}, [subscriptionStatus, refetch, toast]);
|
||||
}, [subscriptionStatus, refetch, toast, router, pathname]);
|
||||
|
||||
async function changeTier(tier: string) {
|
||||
setTierError(null);
|
||||
|
||||
Reference in New Issue
Block a user