Skip to content

Commit 635c42a

Browse files
committed
feat(webapp): admin Coupon Deals route + apply confirmation dialog
1 parent 0314dfa commit 635c42a

2 files changed

Lines changed: 558 additions & 0 deletions

File tree

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import { Form, useNavigation } from "@remix-run/react";
2+
import { Button } from "~/components/primitives/Buttons";
3+
import {
4+
Dialog,
5+
DialogContent,
6+
DialogFooter,
7+
DialogHeader,
8+
} from "~/components/primitives/Dialog";
9+
import { Paragraph } from "~/components/primitives/Paragraph";
10+
import * as Property from "~/components/primitives/PropertyTable";
11+
12+
export type ApplyCouponTarget = {
13+
orgId: string;
14+
orgSlug: string;
15+
orgTitle: string;
16+
planCode: string | null;
17+
subscriptionId: string | null;
18+
stripeCustomerId: string;
19+
stripeCustomerEmail: string;
20+
dealKey: string;
21+
dealLabel: string;
22+
dealCategory: string;
23+
};
24+
25+
type ApplyCouponDialogProps = {
26+
target: ApplyCouponTarget | null;
27+
open: boolean;
28+
onOpenChange: (open: boolean) => void;
29+
};
30+
31+
export function ApplyCouponDialog({ target, open, onOpenChange }: ApplyCouponDialogProps) {
32+
const navigation = useNavigation();
33+
const isSubmitting = navigation.state !== "idle";
34+
35+
return (
36+
<Dialog open={open} onOpenChange={onOpenChange}>
37+
<DialogContent>
38+
<DialogHeader>
39+
{target
40+
? `Apply ${target.dealLabel} to ${target.orgTitle}?`
41+
: "Apply coupon deal"}
42+
</DialogHeader>
43+
44+
{target && (
45+
<>
46+
<Paragraph variant="small" className="text-text-dimmed">
47+
Re-read the org and Stripe customer below before applying. The
48+
coupon will be added to the org's active Stripe subscription.
49+
</Paragraph>
50+
51+
<Property.Table>
52+
<Property.Item>
53+
<Property.Label>Org</Property.Label>
54+
<Property.Value>
55+
{target.orgSlug} · {target.planCode ?? "Free"}
56+
</Property.Value>
57+
</Property.Item>
58+
<Property.Item>
59+
<Property.Label>Stripe customer</Property.Label>
60+
<Property.Value>
61+
{target.stripeCustomerId} ({target.stripeCustomerEmail})
62+
</Property.Value>
63+
</Property.Item>
64+
<Property.Item>
65+
<Property.Label>Stripe sub</Property.Label>
66+
<Property.Value>{target.subscriptionId ?? "—"}</Property.Value>
67+
</Property.Item>
68+
<Property.Item>
69+
<Property.Label>Coupon</Property.Label>
70+
<Property.Value>
71+
{target.dealKey} · {target.dealCategory}
72+
</Property.Value>
73+
</Property.Item>
74+
</Property.Table>
75+
76+
<Form method="post" className="flex flex-col gap-3" reloadDocument>
77+
<input type="hidden" name="intent" value="apply" />
78+
<input type="hidden" name="orgId" value={target.orgId} />
79+
<input type="hidden" name="dealKey" value={target.dealKey} />
80+
81+
<DialogFooter>
82+
<Button
83+
type="button"
84+
variant="tertiary/medium"
85+
onClick={() => onOpenChange(false)}
86+
disabled={isSubmitting}
87+
>
88+
Cancel
89+
</Button>
90+
<Button
91+
type="submit"
92+
variant="primary/medium"
93+
disabled={isSubmitting || !target.subscriptionId}
94+
>
95+
Apply
96+
</Button>
97+
</DialogFooter>
98+
</Form>
99+
</>
100+
)}
101+
</DialogContent>
102+
</Dialog>
103+
);
104+
}

0 commit comments

Comments
 (0)