mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-11-08 12:24:45 +00:00
feat(ui): link usage-limit refusals to Prowler pricing (#13184)
This commit is contained in:
1 parent
c0891591a3
commit
06a20bcc7c
42 files changed
+755
-87
No files matched your search
@@ -2,36 +2,22 @@ import { render, screen } from "@testing-library/react";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { USAGE_LIMIT_MESSAGE } from "@/lib/action-errors";
|
||||
import { BILLING_URL } from "@/lib/external-urls";
|
||||
import { PRICING_URL } from "@/lib/external-urls";
|
||||
|
||||
import { UsageLimitMessage } from "./usage-limit-message";
|
||||
|
||||
describe("UsageLimitMessage", () => {
|
||||
it("renders the shared usage-limit copy", () => {
|
||||
it("explains the limit and opens the plans in a new tab", () => {
|
||||
// When
|
||||
render(<UsageLimitMessage />);
|
||||
|
||||
expect(screen.getByText(/exceeded the usage limit/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("links to Prowler Cloud billing", () => {
|
||||
render(<UsageLimitMessage />);
|
||||
|
||||
const link = screen.getByRole("link", { name: /manage billing/i });
|
||||
expect(link).toHaveAttribute("href", BILLING_URL);
|
||||
// Then
|
||||
expect(
|
||||
screen.getByText(USAGE_LIMIT_MESSAGE, { exact: false }),
|
||||
).toBeVisible();
|
||||
const link = screen.getByRole("link", { name: "View plans" });
|
||||
expect(link).toHaveAttribute("href", PRICING_URL);
|
||||
expect(link).toHaveAttribute("target", "_blank");
|
||||
expect(link).toHaveAttribute("rel", "noopener noreferrer");
|
||||
});
|
||||
|
||||
it("keeps the copy in sync with the 402 action-error message", () => {
|
||||
render(<UsageLimitMessage />);
|
||||
|
||||
expect(screen.getByText(USAGE_LIMIT_MESSAGE)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("merges a custom className with the base styles", () => {
|
||||
const { container } = render(<UsageLimitMessage className="mt-4" />);
|
||||
|
||||
expect(container.firstChild).toHaveClass("mt-4");
|
||||
expect(container.firstChild).toHaveClass("text-text-error-primary");
|
||||
});
|
||||
});
|
||||
@@ -1,25 +1,38 @@
|
||||
import Link from "next/link";
|
||||
|
||||
import { ToastAction } from "@/components/shadcn/toast";
|
||||
import { USAGE_LIMIT_MESSAGE } from "@/lib/action-errors";
|
||||
import { BILLING_URL } from "@/lib/external-urls";
|
||||
import { PRICING_URL } from "@/lib/external-urls";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface UsageLimitMessageProps {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
// Over-limit (trial-expired) notice shown in scan launch flows. Pairs the shared
|
||||
// usage-limit copy with a link to Prowler Cloud billing.
|
||||
const VIEW_PLANS_LABEL = "View plans";
|
||||
|
||||
/** Inline link to Prowler pricing, in a new tab, for copy that explains the refusal itself. */
|
||||
export const ViewPlansLink = () => (
|
||||
<a
|
||||
href={PRICING_URL}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="underline"
|
||||
>
|
||||
{VIEW_PLANS_LABEL}
|
||||
</a>
|
||||
);
|
||||
|
||||
// Over-limit (trial-expired) notice: the shared copy plus Prowler pricing.
|
||||
export const UsageLimitMessage = ({ className }: UsageLimitMessageProps) => (
|
||||
<p className={cn("text-text-error-primary text-sm", className)}>
|
||||
{USAGE_LIMIT_MESSAGE}{" "}
|
||||
<Link
|
||||
href={BILLING_URL}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="underline"
|
||||
>
|
||||
Manage Billing
|
||||
</Link>
|
||||
{USAGE_LIMIT_MESSAGE} <ViewPlansLink />
|
||||
</p>
|
||||
);
|
||||
|
||||
/** Toast action for a usage-limit refusal: Prowler pricing, in a new tab. */
|
||||
export const usageLimitToastAction = () => (
|
||||
<ToastAction altText={VIEW_PLANS_LABEL} asChild>
|
||||
<a href={PRICING_URL} target="_blank" rel="noopener noreferrer">
|
||||
{VIEW_PLANS_LABEL}
|
||||
</a>
|
||||
</ToastAction>
|
||||
);
|
||||
Reference in new issue
Block a user