diff --git a/apps/webapp/app/components/billing/FreePlanUsage.tsx b/apps/webapp/app/components/billing/FreePlanUsage.tsx
new file mode 100644
index 000000000..f81f32944
--- /dev/null
+++ b/apps/webapp/app/components/billing/FreePlanUsage.tsx
@@ -0,0 +1,39 @@
+import { ArrowUpCircleIcon } from "@heroicons/react/24/outline";
+import { motion, useMotionValue, useTransform } from "framer-motion";
+import { Paragraph } from "../primitives/Paragraph";
+import { Link } from "@remix-run/react";
+import { cn } from "~/utils/cn";
+
+export function FreePlanUsage({ to, percentage }: { to: string; percentage: number }) {
+ const widthProgress = useMotionValue(percentage * 100);
+ const color = useTransform(
+ widthProgress,
+ [0, 74, 75, 95, 100],
+ ["#22C55E", "#22C55E", "#F59E0B", "#F43F5E", "#F43F5E"]
+ );
+
+ return (
+
+ );
+}
diff --git a/apps/webapp/app/components/navigation/SideMenu.tsx b/apps/webapp/app/components/navigation/SideMenu.tsx
index 5b8e6acdb..f01705eeb 100644
--- a/apps/webapp/app/components/navigation/SideMenu.tsx
+++ b/apps/webapp/app/components/navigation/SideMenu.tsx
@@ -4,12 +4,10 @@ import {
ChartBarIcon,
EllipsisHorizontalIcon,
} from "@heroicons/react/20/solid";
-import { ArrowUpCircleIcon } from "@heroicons/react/24/outline";
import { UserGroupIcon, UserPlusIcon } from "@heroicons/react/24/solid";
-import { Link, useNavigation } from "@remix-run/react";
+import { useNavigation } from "@remix-run/react";
import { IconExclamationCircle } from "@tabler/icons-react";
import { SlackIcon } from "@trigger.dev/companyicons";
-import { motion, useMotionValue, useTransform } from "framer-motion";
import { AnchorHTMLAttributes, Fragment, useEffect, useRef, useState } from "react";
import { useFeatures } from "~/hooks/useFeatures";
import { MatchedOrganization } from "~/hooks/useOrganizations";
@@ -37,6 +35,7 @@ import { Feedback } from "../Feedback";
import { ImpersonationBanner } from "../ImpersonationBanner";
import { LogoIcon } from "../LogoIcon";
import { UserProfilePhoto } from "../UserProfilePhoto";
+import { FreePlanUsage } from "../billing/FreePlanUsage";
import { Button, LinkButton } from "../primitives/Buttons";
import { Icon } from "../primitives/Icon";
import { type IconNames } from "../primitives/NamedIcon";
@@ -222,7 +221,7 @@ export function SideMenu({ user, project, organization, organizations }: SideMen
}
/>
-
+
@@ -440,37 +439,3 @@ function SideMenuItem({
function MenuCount({ count }: { count: number | string }) {
return {count}
;
}
-
-function FreePlanUsage({ to, percentage }: { to: string; percentage: number }) {
- const widthProgress = useMotionValue(percentage * 100);
- const color = useTransform(
- widthProgress,
- [0, 74, 75, 95, 100],
- ["#22C55E", "#22C55E", "#F59E0B", "#F43F5E", "#F43F5E"]
- );
-
- return (
-
- );
-}
diff --git a/apps/webapp/app/components/stories/FreePlanUsage.stories.tsx b/apps/webapp/app/components/stories/FreePlanUsage.stories.tsx
new file mode 100644
index 000000000..e62477ee3
--- /dev/null
+++ b/apps/webapp/app/components/stories/FreePlanUsage.stories.tsx
@@ -0,0 +1,46 @@
+import type { Meta, StoryObj } from "@storybook/react";
+import { FreePlanUsage } from "../billing/FreePlanUsage";
+import { organizationBillingPath } from "~/utils/pathBuilder";
+import { MatchedOrganization } from "~/hooks/useOrganizations";
+
+const meta: Meta = {
+ title: "Billing/FreePlanUsage",
+ component: FreePlanUsageBar,
+};
+
+export default meta;
+
+type Story = StoryObj;
+
+const mockOrganization: MatchedOrganization = {
+ id: "mockID",
+ title: "mockTitle",
+ slug: "mockSlug",
+ projects: [
+ { id: "mockId1", slug: "mockSlug1", name: "mockName1", jobCount: 1 },
+ { id: "mockId2", slug: "mockSlug2", name: "mockName2", jobCount: 2 },
+ ],
+ hasUnconfiguredIntegrations: false,
+ memberCount: 1,
+};
+
+export const ProgressBar: Story = {
+ args: {
+ organization: mockOrganization,
+ },
+ render: (args) => ,
+};
+
+type FreePlanUsageBarProps = {
+ organization: MatchedOrganization;
+};
+
+function FreePlanUsageBar({ organization }: FreePlanUsageBarProps) {
+ return (
+
+ );
+}