Skip to content

Commit 22efefa

Browse files
committed
WIP making the modal conditional
1 parent d8c1872 commit 22efefa

File tree

2 files changed

+107
-20
lines changed

2 files changed

+107
-20
lines changed

apps/webapp/app/routes/_app.orgs.$organizationSlug.v3.billing/route.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ export default function ChoosePlanPage() {
117117
subscription={v3Subscription}
118118
organizationSlug={organizationSlug}
119119
hasPromotedPlan={false}
120+
periodEnd={periodEnd} // Add this line
120121
/>
121122
</div>
122123
</div>

apps/webapp/app/routes/resources.orgs.$organizationSlug.select-plan.tsx

Lines changed: 106 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
ShieldCheckIcon,
55
XMarkIcon,
66
} from "@heroicons/react/20/solid";
7-
import { Form, useLocation, useNavigation } from "@remix-run/react";
7+
import { Form, useFetcher, useLocation, useNavigation } from "@remix-run/react";
88
import { ActionFunctionArgs } from "@remix-run/server-runtime";
99
import {
1010
FreePlanDefinition,
@@ -34,6 +34,12 @@ import { redirectWithErrorMessage } from "~/models/message.server";
3434
import { setPlan } from "~/services/platform.v3.server";
3535
import { requireUserId } from "~/services/session.server";
3636
import { cn } from "~/utils/cn";
37+
import { useState } from "react";
38+
import { XCircleIcon } from "@heroicons/react/24/outline";
39+
import { DateTime } from "~/components/primitives/DateTime";
40+
import { Header2 } from "~/components/primitives/Headers";
41+
import { CheckboxWithLabel } from "~/components/primitives/Checkbox";
42+
import { TextArea } from "~/components/primitives/TextArea";
3743

3844
const Params = z.object({
3945
organizationSlug: z.string(),
@@ -134,6 +140,7 @@ type PricingPlansProps = {
134140
organizationSlug: string;
135141
hasPromotedPlan: boolean;
136142
showGithubVerificationBadge?: boolean;
143+
periodEnd: Date; // Add this line
137144
};
138145

139146
export function PricingPlans({
@@ -142,6 +149,7 @@ export function PricingPlans({
142149
organizationSlug,
143150
hasPromotedPlan,
144151
showGithubVerificationBadge,
152+
periodEnd, // Add this line
145153
}: PricingPlansProps) {
146154
return (
147155
<div className="flex w-full flex-col">
@@ -151,6 +159,7 @@ export function PricingPlans({
151159
subscription={subscription}
152160
organizationSlug={organizationSlug}
153161
showGithubVerificationBadge={showGithubVerificationBadge}
162+
periodEnd={periodEnd} // Add this line
154163
/>
155164
<TierHobby
156165
plan={plans.hobby}
@@ -172,16 +181,19 @@ export function TierFree({
172181
subscription,
173182
organizationSlug,
174183
showGithubVerificationBadge,
184+
periodEnd, // Add this line
175185
}: {
176186
plan: FreePlanDefinition;
177187
subscription?: SubscriptionResult;
178188
organizationSlug: string;
179189
showGithubVerificationBadge?: boolean;
190+
periodEnd: Date; // Add this line
180191
}) {
181192
const location = useLocation();
182193
const navigation = useNavigation();
183194
const formAction = `/resources/orgs/${organizationSlug}/select-plan`;
184195
const isLoading = navigation.formAction === formAction;
196+
const [isDialogOpen, setIsDialogOpen] = useState(false);
185197

186198
const status = subscription?.freeTierStatus ?? "requires_connect";
187199

@@ -290,25 +302,99 @@ export function TierFree({
290302
</DialogContent>
291303
</Dialog>
292304
) : (
293-
<Button
294-
variant="tertiary/large"
295-
fullWidth
296-
className="text-md font-medium"
297-
disabled={
298-
isLoading ||
299-
subscription?.plan?.type === plan.type ||
300-
subscription?.canceledAt !== undefined
301-
}
302-
LeadingIcon={
303-
isLoading && navigation.formData?.get("planCode") === null ? Spinner : undefined
304-
}
305-
>
306-
{subscription?.plan === undefined
307-
? "Select plan"
308-
: subscription.plan.type === "free" || subscription.canceledAt !== undefined
309-
? "Current plan"
310-
: `Downgrade to ${plan.title}`}
311-
</Button>
305+
<>
306+
{subscription?.plan?.type !== "free" && subscription?.canceledAt === undefined ? (
307+
<>
308+
<Button
309+
variant="tertiary/large"
310+
fullWidth
311+
className="text-md font-medium"
312+
onClick={() => setIsDialogOpen(true)}
313+
>
314+
{`Downgrade to ${plan.title}`}
315+
</Button>
316+
<Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
317+
<DialogContent className="max-w-md">
318+
<DialogHeader>Cancel plan</DialogHeader>
319+
<div className="mb-2 mt-4 flex items-start gap-3">
320+
<span>
321+
<XCircleIcon className="size-12 text-error" />
322+
</span>
323+
<Paragraph variant="base/bright" className="text-text-bright">
324+
Are you sure you want to cancel? If you do, you will retain your current
325+
plan's features until <DateTime includeTime={false} date={periodEnd} />.
326+
</Paragraph>
327+
</div>
328+
<div>
329+
<input type="hidden" name="type" value="free" />
330+
<input type="hidden" name="callerPath" value={location.pathname} />
331+
<div className="mb-4">
332+
<Header2 className="mb-1">Why are you thinking of canceling?</Header2>
333+
<ul className="space-y-1">
334+
{[
335+
"Subscription or usage costs too expensive",
336+
"Bugs or technical issues",
337+
"No longer need the service",
338+
"Found a better alternative",
339+
"Lacking features I need",
340+
].map((label, index) => (
341+
<li key={index}>
342+
<CheckboxWithLabel
343+
id={`reason-${index + 1}`}
344+
name="reason"
345+
value={label}
346+
variant="simple"
347+
label={label}
348+
labelClassName="text-text-dimmed"
349+
/>
350+
</li>
351+
))}
352+
</ul>
353+
</div>
354+
<div className="mb-2">
355+
<Header2 className="mb-1">What can we do to improve?</Header2>
356+
<TextArea id="improvement-suggestions" name="message" />
357+
</div>
358+
</div>
359+
<DialogFooter>
360+
<Button variant="tertiary/medium" onClick={() => setIsDialogOpen(false)}>
361+
Dismiss
362+
</Button>
363+
<Button
364+
variant="danger/medium"
365+
type="submit"
366+
disabled={isLoading}
367+
LeadingIcon={isLoading ? Spinner : undefined}
368+
>
369+
Confirm downgrade
370+
</Button>
371+
</DialogFooter>
372+
</DialogContent>
373+
</Dialog>
374+
</>
375+
) : (
376+
<Button
377+
variant="tertiary/large"
378+
fullWidth
379+
className="text-md font-medium"
380+
disabled={
381+
isLoading ||
382+
subscription?.plan?.type === plan.type ||
383+
subscription?.canceledAt !== undefined
384+
}
385+
LeadingIcon={
386+
isLoading && navigation.formData?.get("planCode") === null
387+
? Spinner
388+
: undefined
389+
}
390+
>
391+
{subscription?.plan === undefined
392+
? "Select plan"
393+
: subscription.plan.type === "free" ||
394+
(subscription.canceledAt !== undefined && "Current plan")}
395+
</Button>
396+
)}
397+
</>
312398
)}
313399
</div>
314400
<ul className="flex flex-col gap-2.5">

0 commit comments

Comments
 (0)