Skip to content

Commit

Permalink
Upgrading from Hobby to Pro displays a dialog to confirm (#1545)
Browse files Browse the repository at this point in the history
* Upgrading from Hobby to Pro displays a dialog to confirm

* Improved the logic for upgrading to pro

* Added the spinner component to storybook

* Improved the dark style spinner
  • Loading branch information
samejr authored Dec 13, 2024
1 parent 6516e15 commit c58f6f7
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 24 deletions.
4 changes: 2 additions & 2 deletions apps/webapp/app/components/primitives/Spinner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ export function Spinner({
foreground: "#3C4B62",
},
dark: {
background: "#15171A",
foreground: "#272A2E",
background: "rgba(18, 19, 23, 0.35)",
foreground: "#1A1B1F",
},
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
ShieldCheckIcon,
XMarkIcon,
} from "@heroicons/react/20/solid";
import { ArrowDownCircleIcon } from "@heroicons/react/24/outline";
import { ArrowDownCircleIcon, ArrowUpCircleIcon } from "@heroicons/react/24/outline";
import { Form, useLocation, useNavigation } from "@remix-run/react";
import { ActionFunctionArgs } from "@remix-run/server-runtime";
import { uiComponent } from "@team-plain/typescript-sdk";
Expand Down Expand Up @@ -633,6 +633,11 @@ export function TierPro({
const navigation = useNavigation();
const formAction = `/resources/orgs/${organizationSlug}/select-plan`;
const isLoading = navigation.formAction === formAction;
const [isDialogOpen, setIsDialogOpen] = useState(false);

useEffect(() => {
setIsDialogOpen(false);
}, [subscription]);

return (
<TierContainer>
Expand All @@ -645,27 +650,67 @@ export function TierPro({
<input type="hidden" name="type" value="paid" />
<input type="hidden" name="planCode" value={plan.code} />
<input type="hidden" name="callerPath" value={location.pathname} />
<Button
variant="tertiary/large"
fullWidth
form="subscribe-pro"
className="text-md font-medium"
disabled={
isLoading ||
(subscription?.plan?.code === plan.code && subscription.canceledAt === undefined)
}
LeadingIcon={
isLoading && navigation.formData?.get("planCode") === plan.code ? Spinner : undefined
}
>
{subscription?.plan === undefined
? "Select plan"
: subscription.plan.type === "free" || subscription.canceledAt !== undefined
? `Upgrade to ${plan.title}`
: subscription.plan.code === plan.code
? "Current plan"
: `Upgrade to ${plan.title}`}
</Button>
{subscription?.plan !== undefined &&
subscription?.plan?.type === "paid" &&
subscription?.plan?.code !== plan.code &&
subscription.canceledAt === undefined ? (
<Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen} key="upgrade">
<DialogTrigger asChild>
<Button variant="tertiary/large" fullWidth className="text-md font-medium">
{`Upgrade to ${plan.title}`}
</Button>
</DialogTrigger>
<DialogContent className="sm:max-w-md">
<DialogHeader>Upgrade plan?</DialogHeader>
<div className="mb-2 mt-4 flex items-start gap-3">
<span>
<ArrowUpCircleIcon className="size-12 text-primary" />
</span>
<Paragraph variant="base/bright" className="text-text-bright">
Are you sure you want to upgrade to the Pro plan? You will be charged the new
plan price for the remainder of this month on a pro rata basis.
</Paragraph>
</div>
<DialogFooter>
<Button variant="tertiary/medium" onClick={() => setIsDialogOpen(false)}>
Cancel
</Button>
<Button
variant="primary/medium"
disabled={isLoading}
LeadingIcon={isLoading ? () => <Spinner color="dark" /> : undefined}
form="subscribe-pro"
>
{`Upgrade to ${plan.title}`}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
) : (
<Button
variant="tertiary/large"
fullWidth
form="subscribe-pro"
className="text-md font-medium"
disabled={
isLoading ||
(subscription?.plan?.code === plan.code && subscription.canceledAt === undefined)
}
LeadingIcon={
isLoading && navigation.formData?.get("planCode") === plan.code
? Spinner
: undefined
}
>
{subscription?.plan === undefined
? "Select plan"
: subscription.plan.type === "free" || subscription.canceledAt !== undefined
? `Upgrade to ${plan.title}`
: subscription.plan.code === plan.code
? "Current plan"
: `Upgrade to ${plan.title}`}
</Button>
)}
</div>
</Form>
<ul className="flex flex-col gap-2.5">
Expand Down
28 changes: 28 additions & 0 deletions apps/webapp/app/routes/storybook.spinner/route.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Spinner } from "~/components/primitives/Spinner";

export default function Story() {
return (
<div className="flex flex-col items-start gap-y-3 p-4">
<div className="flex items-center gap-x-4 rounded-md bg-charcoal-750 px-3 py-2 text-text-bright">
Blue: <Spinner color="blue" />
</div>
<div className="flex items-center gap-x-4 rounded-md bg-charcoal-750 px-3 py-2 text-text-bright">
White: <Spinner color="white" />
</div>
<div className="flex items-center gap-x-4 rounded-md bg-charcoal-600 px-3 py-2 text-text-bright">
Muted: <Spinner color="muted" />
</div>
<div className="flex items-center gap-x-2">
<div className="flex items-center gap-x-4 rounded-md bg-charcoal-600 px-3 py-2 text-text-bright">
Dark: <Spinner color="dark" />
</div>
<div className="flex items-center gap-x-4 rounded-md bg-primary px-2 py-2 text-text-bright">
<Spinner color="dark" />
</div>
</div>
<div className="flex items-center gap-x-4 rounded-md bg-charcoal-600 px-3 py-2 text-text-bright">
Custom: <Spinner color={{ background: "#EA189E", foreground: "#6532F5" }} />
</div>
</div>
);
}
4 changes: 4 additions & 0 deletions apps/webapp/app/routes/storybook/route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ const stories: Story[] = [
name: "Shortcuts",
slug: "shortcuts",
},
{
name: "Spinners",
slug: "spinner",
},
{
name: "Switch",
slug: "switch",
Expand Down

0 comments on commit c58f6f7

Please sign in to comment.