Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Billing #789

Merged
merged 128 commits into from
Dec 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
128 commits
Select commit Hold shift + click to select a range
0725dd8
Initial commit - started work on new billing components
samejr Nov 17, 2023
0e06936
Added a slider component
samejr Nov 17, 2023
6c884e9
Added features to the pricing tiers
samejr Nov 17, 2023
b71b91c
Small pricing tier margin tweaks
samejr Nov 20, 2023
8da009d
WIP on a concurrecy chart
samejr Nov 20, 2023
c4d54d2
Reworked the pricing tiers to include a segmented controller and tool…
samejr Nov 22, 2023
04b82e4
Renamed the charts storybook page
samejr Nov 22, 2023
b58d96d
Made the way data is added more flexible and added some definition to…
samejr Nov 22, 2023
bc079a3
Term definitions are used properly in the tiers
samejr Nov 22, 2023
d023071
Callouts can now have an optional CTA on the right hand side
samejr Nov 23, 2023
e5da49f
Alignment fix for the callouts
samejr Nov 23, 2023
13e408c
organize imports
samejr Nov 23, 2023
bed687f
Definition tooltip now its own component
samejr Nov 23, 2023
8b10310
renamed the storybook story
samejr Nov 23, 2023
5347c78
WIP new volume discount table and usage sliders
samejr Nov 23, 2023
56dfa7b
Added pricing calculator sliders
samejr Nov 23, 2023
1db5a85
Fixed alignment of the legend
samejr Nov 23, 2023
c1a44d9
Breadcrumb now has an upgrade prompt and button
samejr Nov 23, 2023
459e3e6
New Join our Slack button in the side menu
samejr Nov 23, 2023
7bb35d7
New progress meter in the side menu
samejr Nov 23, 2023
c08c38b
Use the highest of 2 values to show progress
samejr Nov 23, 2023
e27a634
An attempt to fix the step count in the calculator slider
samejr Nov 24, 2023
eb0df5e
WIP usage progress bar
samejr Nov 24, 2023
54fbe4c
Added the 4 progress bars
samejr Nov 24, 2023
4e68a7d
More examples of the usage bar
samejr Nov 24, 2023
8e71e41
Better way to include the percentage in the free plan progress meter
samejr Nov 24, 2023
1769cce
The usage bar now works with the extra runs over the free limit
samejr Nov 24, 2023
935849d
Pricing calculator has better slider logic
samejr Nov 24, 2023
dd585f9
Moved the free plan usage bar into it’s own component and added it to…
samejr Nov 28, 2023
366a7dc
Usage bar chart now supports a paying customer option and optional bi…
samejr Nov 28, 2023
cc72f14
Added more examples of usage to storybook
samejr Nov 28, 2023
e7fa475
tooltip takes classname
samejr Nov 28, 2023
86589f5
Format numbers nicely
samejr Nov 28, 2023
c8ac5d9
Added a tooltip to show the precise numbers in the chart
samejr Nov 28, 2023
f2bf69b
small improvements to the billing calculator
samejr Nov 28, 2023
26445ca
New onboarding choose plan page
samejr Nov 28, 2023
fa6b03f
pricing tiers better fill the size of their container
samejr Nov 28, 2023
063fcdd
Removed unused code
samejr Nov 29, 2023
f19dddb
Usage bars animate
samejr Nov 29, 2023
254ad74
Wording tweak
samejr Nov 29, 2023
ff178e1
Callouts fit the button size better
samejr Nov 29, 2023
17f043b
Added new routes for the 2 new billing pages
samejr Nov 29, 2023
00b61d3
import cleanup
samejr Nov 30, 2023
8ad9107
Added meta info in the header for bill price, plan type and billing p…
samejr Nov 30, 2023
1359fc5
made free a noun
samejr Nov 30, 2023
5e511b9
Added pricing calculator to the plans page
samejr Nov 30, 2023
10fbd4a
Fixed some illegal markup when using tooltips
samejr Nov 30, 2023
cba1b36
Added container query support
samejr Nov 30, 2023
68ceafa
Added new concurrency chart to the usage page
samejr Nov 30, 2023
f559bb7
billing now has a green theme
samejr Nov 30, 2023
be51eb6
Simplified the plan summary info int the header
samejr Nov 30, 2023
a8f75f7
Fixed padding alignment
samejr Nov 30, 2023
5936f33
Use a custom lable for the concurrent runs chart
samejr Nov 30, 2023
9ca4792
Removed the Job runs table
samejr Nov 30, 2023
a662431
Merge remote-tracking branch 'origin/main' into features/billing
matt-aitken Nov 30, 2023
6f67c9f
Latest lockfile
matt-aitken Nov 30, 2023
5368ee2
Show a message if you haven’t done runs yet
samejr Nov 30, 2023
0cafa86
Added a layoutId to the pageTabs
samejr Nov 30, 2023
d94eee0
Show a message callout if you’ve exceeeded 10k runs on the free plan
samejr Dec 1, 2023
1e5c1ab
Added a callout on the plans page if you’re over the runs limit
samejr Dec 1, 2023
8c60ea3
Fixed button inside button bug
samejr Dec 1, 2023
00746ae
Removed the background gradients from the app
samejr Dec 1, 2023
46a83e9
The billing package is importing properly
matt-aitken Dec 1, 2023
ec7303a
Getting the curent plan for an org
matt-aitken Dec 1, 2023
7c2780e
Reading the current plan and usage
matt-aitken Dec 1, 2023
181c3ee
Hooked up the free plan bar
matt-aitken Dec 1, 2023
7e4cb7f
Render basic billing details
matt-aitken Dec 1, 2023
286fc19
vol discount table has optional values
samejr Dec 1, 2023
3a06e43
Added a new page to show new subscribers
samejr Dec 1, 2023
00a4066
Created a new hook for confetti on the subscribed page
samejr Dec 1, 2023
a7d8234
Toast styling updated
samejr Dec 1, 2023
d68bd97
The Invoice and Manage card details links are working
matt-aitken Dec 1, 2023
aed0ce6
Meta appEnv data optional
matt-aitken Dec 1, 2023
c1480ce
Data for the plans page
matt-aitken Dec 1, 2023
f995586
Format the billing period duration in days
matt-aitken Dec 1, 2023
dc6faf9
Switch to 20 icons
matt-aitken Dec 1, 2023
a0483a0
URL for the subscribed page now includes the org path
samejr Dec 1, 2023
3ae5843
New pathBuilder path for the subscribed page
samejr Dec 1, 2023
79cc63a
Plans are upgraded/downgraded successfully
matt-aitken Dec 1, 2023
ed2ef7d
Fixed badly named paths
matt-aitken Dec 1, 2023
8db4d9d
Improved some of the display
matt-aitken Dec 1, 2023
805256a
Deal with when the user has canceled so they can re-upgrade
matt-aitken Dec 1, 2023
6f3e946
Subscribing from Stripe is working, and canceling
matt-aitken Dec 1, 2023
af7dcb1
Tidied up some bits, latest billing package
matt-aitken Dec 1, 2023
af09a8e
The tiers are now rendering using the real data
matt-aitken Dec 1, 2023
bae2b05
The onboarding screen is hooked up, but not linked to yet
matt-aitken Dec 1, 2023
6101084
Onboarding price selection working
matt-aitken Dec 3, 2023
b59010e
Pricing slider working
matt-aitken Dec 3, 2023
bd79f83
Price estimation working
matt-aitken Dec 3, 2023
0e58ffd
Pricing calculator working on the select a plan page
matt-aitken Dec 4, 2023
2f627f8
Button copy change
samejr Dec 4, 2023
c64b411
Improved the layout of the run calculator marker
matt-aitken Dec 4, 2023
b64bf19
Fix for the period end when you’ve canceled
matt-aitken Dec 4, 2023
890c501
Improved the formatting in the calculator
matt-aitken Dec 4, 2023
cde232a
Pricing table tooltip uses the vol discount pricing table
samejr Dec 4, 2023
1b77701
Remove the vertical lines from the calculator
samejr Dec 4, 2023
b1ebca0
Contact us button in Enterprise tier opens the contact us form
samejr Dec 4, 2023
8ab47a4
Added composite index to triggerdotdev_events.run_executions for even…
matt-aitken Dec 4, 2023
5ca6591
Merge remote-tracking branch 'origin/main' into features/billing
matt-aitken Dec 4, 2023
fc922cb
Concurrent run chart data
matt-aitken Dec 4, 2023
d684e51
Improves styling, fix for React error with Enterprise contact button
matt-aitken Dec 4, 2023
b8a9d63
Show warning box when you’ve hit the concurrency in the past 30 days
matt-aitken Dec 4, 2023
907dbee
Lots of work o the usage page
matt-aitken Dec 5, 2023
e113d6e
Improvements to the usage page
matt-aitken Dec 5, 2023
5a63101
Show 31 days of data, fix for not showing the current date…
matt-aitken Dec 5, 2023
d202705
Stripe portal links are generated when the user clicks through
matt-aitken Dec 5, 2023
4b09943
Better alignment of the reference line and x-axis label
samejr Dec 5, 2023
b88dc52
Readme update
samejr Dec 5, 2023
0b40ddd
Fixed pricing button loading buttons
matt-aitken Dec 5, 2023
be57dbb
Show warnings about concurrency and runs on the plans page
matt-aitken Dec 5, 2023
33a0c3f
Removed some storybook stories
samejr Dec 5, 2023
ced819b
Join Slack channel shows if you’re subscribed with instructions
samejr Dec 5, 2023
15e711c
Added a gap between the runs charts
samejr Dec 5, 2023
b691c4c
Improved the definitions
matt-aitken Dec 5, 2023
06bc91a
Added some margin to the page loading spinner
samejr Dec 5, 2023
6fcfa51
A wider, cleaner feedback panel
samejr Dec 5, 2023
8c93744
Modal backgrounds match the Sheet style
samejr Dec 5, 2023
b197d90
Fixed menu item text being clipped
samejr Dec 6, 2023
a6988c1
Improved icons for execution time and exclusion count
samejr Dec 6, 2023
6bf14b9
Concurrency chart now renders the dates nicely
matt-aitken Dec 6, 2023
caeacc6
Fix for plans data on the plans page
samejr Dec 6, 2023
e65fc77
The healthcheck doesn’t need to do a HEAD request to /
matt-aitken Dec 7, 2023
0b43e72
Better disabled states and fixed the disabled hover state issue
samejr Dec 12, 2023
3a1a6e8
Improved the segmented controller style
samejr Dec 12, 2023
dcf5b42
loading spinner now centered inside the button
samejr Dec 12, 2023
ce702b0
Redirect to the project page when selecting the free plan
matt-aitken Dec 12, 2023
08ed4b0
Fix for “Runs” and added real date to upgrade warning
matt-aitken Dec 12, 2023
266c279
DeCAPITALIZED some things
matt-aitken Dec 12, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
33 changes: 33 additions & 0 deletions apps/webapp/app/components/DefinitionTooltip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Header3 } from "./primitives/Headers";
import { Paragraph } from "./primitives/Paragraph";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "./primitives/Tooltip";

export function DefinitionTip({
content,
children,
title,
}: {
content: React.ReactNode;
children: React.ReactNode;
title: React.ReactNode;
}) {
return (
<TooltipProvider>
<Tooltip disableHoverableContent>
<TooltipTrigger>
<span className="underline decoration-slate-600 decoration-dashed underline-offset-4 transition hover:decoration-slate-500">
{children}
</span>
</TooltipTrigger>
<TooltipContent align="end" side="right" variant="dark" className="w-[16rem] min-w-[16rem]">
<Header3 className="mb-1">{title}</Header3>
{typeof content === "string" ? (
<Paragraph variant="small">{content}</Paragraph>
) : (
<div>{content}</div>
)}
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
}
47 changes: 24 additions & 23 deletions apps/webapp/app/components/Feedback.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { conform, useForm } from "@conform-to/react";
import { parse } from "@conform-to/zod";
import { ChevronRightIcon } from "@heroicons/react/24/solid";
import { Form, useActionData, useLocation, useNavigation } from "@remix-run/react";
import { DiscordIcon } from "@trigger.dev/companyicons";
import { ReactNode, useState } from "react";
import { FeedbackType, feedbackTypeLabel, schema } from "~/routes/resources.feedback";
import { Button } from "./primitives/Buttons";
import { Fieldset } from "./primitives/Fieldset";
import { FormButtons } from "./primitives/FormButtons";
import { FormError } from "./primitives/FormError";
import { Header2 } from "./primitives/Headers";
import { InputGroup } from "./primitives/InputGroup";
import { Label } from "./primitives/Label";
import { Paragraph } from "./primitives/Paragraph";
Expand All @@ -20,8 +23,6 @@ import {
} from "./primitives/Select";
import { Sheet, SheetBody, SheetContent, SheetHeader, SheetTrigger } from "./primitives/Sheet";
import { TextArea } from "./primitives/TextArea";
import { DiscordIcon } from "@trigger.dev/companyicons";
import { ChevronRightIcon } from "@heroicons/react/24/solid";

type FeedbackProps = {
button: ReactNode;
Expand Down Expand Up @@ -55,19 +56,16 @@ export function Feedback({ button, defaultValue = "bug" }: FeedbackProps) {
return (
<Sheet open={open} onOpenChange={setOpen}>
<SheetTrigger asChild={true}>{button}</SheetTrigger>
<SheetContent size="sm">
<SheetHeader className="justify-between">Help & feedback</SheetHeader>
<SheetBody>
<SheetContent>
<SheetHeader className="justify-between">How can we help?</SheetHeader>
<SheetBody className="flex h-full flex-col justify-between">
<DiscordBanner />
<Paragraph variant="small" className="mb-4 border-t border-slate-800 pt-3">
Or use this form to ask for help or give us feedback. We read every message and will get
back to you as soon as we can.
</Paragraph>
<hr className="mb-3" />
<Header2 className="mb-4">Send us a message</Header2>
<Form method="post" action="/resources/feedback" {...form.props}>
<Fieldset className="max-w-full">
<input value={location.pathname} {...conform.input(path, { type: "hidden" })} />
<InputGroup className="max-w-full">
<Label>How can we help?</Label>
<SelectGroup>
<Select {...conform.input(feedbackType)} defaultValue={defaultValue}>
<SelectTrigger size="medium" width="full">
Expand All @@ -90,14 +88,19 @@ export function Feedback({ button, defaultValue = "bug" }: FeedbackProps) {
<FormError id={message.errorId}>{message.error}</FormError>
</InputGroup>
<FormError>{form.error}</FormError>
<FormButtons
className="w-full"
confirmButton={
<Button type="submit" variant="primary/medium">
Send
</Button>
}
/>
<div className="flex w-full items-center justify-between">
<Paragraph variant="small" className="w-full">
We read every message and respond quickly.
</Paragraph>
<FormButtons
className="m-0 w-max"
confirmButton={
<Button type="submit" variant="primary/medium">
Send
</Button>
}
/>
</div>
</Fieldset>
</Form>
</SheetBody>
Expand All @@ -109,7 +112,7 @@ export function Feedback({ button, defaultValue = "bug" }: FeedbackProps) {
function DiscordBanner() {
return (
<a
href="https://discord.gg/nkqV9xBYWy"
href="https://trigger.dev/discord"
target="_blank"
className="group mb-4 flex w-full items-center justify-between rounded-md border border-slate-600 bg-gradient-to-br from-blue-400/30 to-indigo-400/50 p-4 transition hover:border-indigo-400"
>
Expand All @@ -120,13 +123,11 @@ function DiscordBanner() {
<br />
Discord community
</h2>
<Paragraph variant="small">
<Paragraph variant="small/bright">
Get help or answer questions from the Trigger.dev community.
</Paragraph>
</div>
<div className="h-full">
<ChevronRightIcon className="h-5 w-5 text-slate-400 transition group-hover:translate-x-1 group-hover:text-indigo-400" />
</div>
<ChevronRightIcon className="h-5 w-5 text-slate-400 transition group-hover:translate-x-1 group-hover:text-indigo-400" />
</a>
);
}
12 changes: 0 additions & 12 deletions apps/webapp/app/components/PageGradient.tsx

This file was deleted.

114 changes: 114 additions & 0 deletions apps/webapp/app/components/billing/ConcurrentRunsChart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import {
Label,
Line,
LineChart,
ReferenceLine,
ResponsiveContainer,
Tooltip,
XAxis,
YAxis,
} from "recharts";
import { Paragraph } from "../primitives/Paragraph";

const tooltipStyle = {
display: "flex",
alignItems: "center",
gap: "0.5rem",
borderRadius: "0.25rem",
border: "1px solid #1A2434",
backgroundColor: "#0B1018",
padding: "0.3rem 0.5rem",
fontSize: "0.75rem",
color: "#E2E8F0",
};

type DataItem = { date: Date; maxConcurrentRuns: number };

const dateFormatter = new Intl.DateTimeFormat("en-US", {
month: "short",
day: "numeric",
});

export function ConcurrentRunsChart({
concurrentRunsLimit,
data,
hasConcurrencyData,
}: {
concurrentRunsLimit?: number;
data: DataItem[];
hasConcurrencyData: boolean;
}) {
return (
<div className="relative">
{!hasConcurrencyData && (
<Paragraph className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2">
No concurrent Runs to show
</Paragraph>
)}
<ResponsiveContainer width="100%" height="100%" className="relative min-h-[20rem]">
<LineChart
data={data}
margin={{
top: 20,
right: 0,
left: 0,
bottom: 10,
}}
className="-ml-8"
>
<XAxis
stroke="#94A3B8"
fontSize={12}
tickLine={false}
axisLine={false}
dataKey={(item: DataItem) => {
if (item.date.getDate() === 1) {
return dateFormatter.format(item.date);
}
return `${item.date.getDate()}`;
}}
className="text-xs"
>
<Label value="Last 30 days" offset={-8} position="insideBottom" fill="#94A3B8" />
</XAxis>
<YAxis stroke="#94A3B8" fontSize={12} tickLine={false} axisLine={false} />
<Tooltip
cursor={{ fill: "rgba(255,255,255,0.05)" }}
contentStyle={tooltipStyle}
labelFormatter={(value, data) => {
const date = data.at(0)?.payload.date;
if (!date) {
return "";
}
return dateFormatter.format(date);
}}
/>
{concurrentRunsLimit && (
<ReferenceLine
y={concurrentRunsLimit}
stroke="#F43F5E"
strokeWidth={1}
strokeDasharray={5}
ifOverflow="extendDomain"
className="text-xs"
>
<Label
value="Concurrent Runs limit"
offset={8}
position="insideTopLeft"
fill="#F43F5E"
/>
</ReferenceLine>
)}
<Line
dataKey="maxConcurrentRuns"
name="Concurrent runs"
stroke="#16A34A"
strokeWidth={2}
dot={false}
/>
</LineChart>
</ResponsiveContainer>
</div>
);
}
40 changes: 40 additions & 0 deletions apps/webapp/app/components/billing/FreePlanUsage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
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 cappedPercentage = Math.min(percentage, 1);
const widthProgress = useMotionValue(cappedPercentage * 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: cappedPercentage * 100 + "%" }}
style={{
backgroundColor: color,
}}
transition={{ duration: 1, type: "spring" }}
className={cn("absolute left-0 top-0 h-full rounded-full")}
/>
</div>
</div>
);
}
Loading
Loading