Moved the free plan usage bar into it’s own component and added it to storybook
This commit is contained in:
@@ -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 (
|
||||
<div className="rounded border border-slate-900 bg-[#101722] p-2.5">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<div className="flex items-center gap-1">
|
||||
<ArrowUpCircleIcon className="h-5 w-5 text-dimmed" />
|
||||
<Paragraph className="text-2sm text-bright">Free Plan</Paragraph>
|
||||
</div>
|
||||
<Link to={to} className="text-2sm text-indigo-500">
|
||||
Learn more
|
||||
</Link>
|
||||
</div>
|
||||
<div className="relative mt-3 h-1 rounded-full bg-[#0B1018]">
|
||||
<motion.div
|
||||
initial={{ width: 0 }}
|
||||
animate={{ width: percentage * 100 + "%" }}
|
||||
style={{
|
||||
backgroundColor: color,
|
||||
}}
|
||||
transition={{ duration: 1, type: "spring" }}
|
||||
className={cn("absolute left-0 top-0 h-full rounded-full")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -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
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
<FreePlanUsage to={organizationBillingPath(organization)} percentage={0.95} />
|
||||
<FreePlanUsage to={organizationBillingPath(organization)} percentage={0.75} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -440,37 +439,3 @@ function SideMenuItem({
|
||||
function MenuCount({ count }: { count: number | string }) {
|
||||
return <div className="rounded-full bg-slate-900 px-2 py-1 text-xxs text-dimmed">{count}</div>;
|
||||
}
|
||||
|
||||
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 (
|
||||
<div className="rounded border border-slate-900 bg-[#101722] p-2.5">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-1">
|
||||
<ArrowUpCircleIcon className="h-5 w-5 text-dimmed" />
|
||||
<Paragraph className="text-2sm text-bright">Free Plan</Paragraph>
|
||||
</div>
|
||||
<Link to={to} className="text-2sm text-indigo-500">
|
||||
Learn more
|
||||
</Link>
|
||||
</div>
|
||||
<div className="relative mt-3 h-1 rounded-full bg-[#0B1018]">
|
||||
<motion.div
|
||||
initial={{ width: 0 }}
|
||||
animate={{ width: percentage * 100 + "%" }}
|
||||
style={{
|
||||
backgroundColor: color,
|
||||
}}
|
||||
transition={{ duration: 1, type: "spring" }}
|
||||
className={cn("absolute left-0 top-0 h-full rounded-full")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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<typeof FreePlanUsageBar> = {
|
||||
title: "Billing/FreePlanUsage",
|
||||
component: FreePlanUsageBar,
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
type Story = StoryObj<typeof FreePlanUsageBar>;
|
||||
|
||||
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) => <FreePlanUsageBar {...args} />,
|
||||
};
|
||||
|
||||
type FreePlanUsageBarProps = {
|
||||
organization: MatchedOrganization;
|
||||
};
|
||||
|
||||
function FreePlanUsageBar({ organization }: FreePlanUsageBarProps) {
|
||||
return (
|
||||
<div className="flex h-screen flex-col items-center justify-center p-12">
|
||||
<div className="w-fit">
|
||||
<FreePlanUsage to={organizationBillingPath(organization)} percentage={0.75} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user