Skip to content

Commit

Permalink
feat: add Cron usage and tRPC usage APIs (#563)
Browse files Browse the repository at this point in the history
* feat: integrate tinybird

* feat: add usage pipe

* fix: date_from

* feat: init mailing template

* feat: add mailing components and templates

* feat: send usage exceeded email

* fix: add emails files

* fix: build errors

* feat: add trpc usage api

* fix: build error

* fix: cyDarjs imports

* fix: tsconfig includes
  • Loading branch information
devrsi0n authored Feb 9, 2023
1 parent ed1e10f commit 01288c3
Show file tree
Hide file tree
Showing 65 changed files with 3,216 additions and 660 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/bundle-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,6 @@ jobs:
PROJECT_ID_VERCEL: ${{ secrets.PROJECT_ID_VERCEL }}
AUTH_BEARER_TOKEN: ${{ secrets.AUTH_BEARER_TOKEN }}
EMAIL_API_KEY: ${{ secrets.EMAIL_API_KEY }}
NEXT_PUBLIC_TINYBIRD_FLOCK_TOKEN: ${{ secrets.NEXT_PUBLIC_TINYBIRD_FLOCK_TOKEN }}
TINYBIRD_ADMIN_TOKEN: ${{ secrets.TINYBIRD_ADMIN_TOKEN }}
QSTASH_NEXT_SIGNING_KEY: ${{ secrets.QSTASH_NEXT_SIGNING_KEY }}
QSTASH_CURRENT_SIGNING_KEY: ${{ secrets.QSTASH_CURRENT_SIGNING_KEY }}
4 changes: 4 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,17 @@
"grayl",
"jsonb",
"maizzle",
"Mjml",
"pnpm",
"QSTASH",
"rehype",
"Shiki's",
"signin",
"tfjs",
"trpc",
"tsconfigs",
"tsup",
"uglifyjs",
"visx",
"whitea",
"wonka"
Expand Down
2 changes: 1 addition & 1 deletion apps/comment-bootstrapper/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"jest": "29.4.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"typescript": "4.9.4",
"typescript": "4.9.5",
"vite": "2.9.14"
},
"publishConfig": {
Expand Down
2 changes: 1 addition & 1 deletion apps/e2e/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"dotenv-cli": "6.0.0",
"dotenv-expand": "9.0.0",
"eslint": "8.33.0",
"typescript": "4.9.4"
"typescript": "4.9.5"
},
"publishConfig": {
"access": "public"
Expand Down
4 changes: 2 additions & 2 deletions apps/main/.env-tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,5 @@ TWITTER_CONSUMER_SECRET=
# Copy the id of cypress test user, find it in your db
TEST_USER_ID=

# Tinybird flock token, used by analytics
NEXT_PUBLIC_TINYBIRD_FLOCK_TOKEN=
# Tinybird admin token, used by analytics
TINYBIRD_ADMIN_TOKEN=
1 change: 1 addition & 0 deletions apps/main/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# For local debugging
/public/tf-models
.mailing
6 changes: 6 additions & 0 deletions apps/main/emails/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
rules: {
'unicorn/filename-case': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
},
};
58 changes: 58 additions & 0 deletions apps/main/emails/ExceededUsage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { SUPPORT_LINK } from '@chirpy-dev/utils';
import { MjmlColumn, MjmlSection } from 'mjml-react';
import React from 'react';

import BaseLayout from './components/base-layout';
import Button from './components/button';
import Footer from './components/footer';
import Header from './components/header';
import Link from './components/link';
import Text from './components/text';

export type ExceededUsageProps = {
userName?: string | null;
usage: number;
usageLimit: number;
plan: string;
};

export default function ExceededUsage({
userName,
usage,
usageLimit,
plan,
}: ExceededUsageProps): JSX.Element {
return (
<BaseLayout width={500}>
<Header />
<MjmlSection>
<MjmlColumn>
<Text>Hi {userName || 'there'}!</Text>
<Text>
Just wanted to reach out and let you know that your account has
exceeded the
<strong> {plan} Plan </strong>
limit of <strong>{usageLimit} page views</strong>. You have used{' '}
<strong>{usage} page views</strong> across all your projects in your
current billing cycle.
</Text>
<Text>
{`All your existing pages will continue to work, and we're still
collecting data on them, but you'll need to upgrade to view their
stats, edit them, or publish new content.`}
</Text>
<Button href={`https://app.chirpy.dev/billing`}>
Upgrade my plan
</Button>
<Text paddingTop={32}>
{`Feel free to ignore this email if you don't plan on upgrading, or send an email to `}
<Link href={SUPPORT_LINK}>Chirpy Support</Link>
{` if you have any
questions!`}
</Text>
</MjmlColumn>
</MjmlSection>
<Footer />
</BaseLayout>
);
}
1 change: 1 addition & 0 deletions apps/main/emails/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
We have to put emails components here or there will be a build error due to uglifyjs can't find the files.
110 changes: 110 additions & 0 deletions apps/main/emails/components/base-layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import {
Mjml,
MjmlBody,
MjmlHead,
MjmlStyle,
MjmlAttributes,
MjmlAll,
} from 'mjml-react';
import React from 'react';

import {
screens,
themeDefaults,
spacing,
colors,
fontFamily,
fontSize,
borderRadius,
} from '../theme';

type BaseLayoutProps = {
width?: number;
style?: string;
children: React.ReactNode;
};

export default function BaseLayout({
width,
children,
style,
}: BaseLayoutProps) {
return (
<Mjml>
<MjmlHead>
<MjmlAttributes>
<MjmlAll {...themeDefaults} />
</MjmlAttributes>
<MjmlStyle>{`
body {
-webkit-font-smoothing: antialiased;
min-width: 320px;
background-color: ${colors.gray[100]};
color: ${colors.gray[1200]};
}
a {
color: inherit
}
.gutter {
padding-left: ${spacing.s7}px;
padding-right: ${spacing.s7}px;
}
.code {
font-family: ${fontFamily.mono};
color: ${colors.pink[200]};
background-color: ${colors.pink[900]};
font-size: ${fontSize.sm}px;
border-radius: ${borderRadius.sm}px;
padding: ${spacing.s1}px ${spacing.s3}px;
}
.no-wrap {
white-space: nowrap;
}
.hidden {
display: none;
max-width: 0px;
max-height: 0px;
overflow: hidden;
mso-hide: all;
}
.lg-hidden {
display: none;
max-width: 0px;
max-height: 0px;
overflow: hidden;
mso-hide: all;
}
/* Large screens */
@media (min-width:${screens.xs}) {
.gutter {
padding-left: ${spacing.s9}px;
padding-right: ${spacing.s9}px;
}
.sm-hidden {
display: none;
max-width: 0px;
max-height: 0px;
overflow: hidden;
mso-hide: all;
}
.lg-hidden {
display: block !important;
max-width: none !important;
max-height: none !important;
overflow: visible !important;
mso-hide: none !important;
}
}
/* Email specific Styles */
${style}
`}</MjmlStyle>
</MjmlHead>

<MjmlBody width={width} cssClass="gutter">
{children}
</MjmlBody>
</Mjml>
);
}
30 changes: 30 additions & 0 deletions apps/main/emails/components/button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import cx from 'classnames';
import { MjmlButton } from 'mjml-react';
import React from 'react';

import {
colors,
fontSize,
borderRadius,
lineHeight,
fontWeight,
} from '../theme';

type ButtonProps = React.ComponentProps<typeof MjmlButton>;

export default function Button(props: ButtonProps) {
return (
<MjmlButton
lineHeight={lineHeight.tight}
fontSize={fontSize.base}
fontWeight={fontWeight.bold}
innerPadding="10px 16px"
align="left"
backgroundColor={colors.primary[900]}
color={colors.primary[100]}
borderRadius={borderRadius.sm}
cssClass={cx('button', props.cssClass)}
{...props}
/>
);
}
45 changes: 45 additions & 0 deletions apps/main/emails/components/footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { EMAIL_PREFERENCES_URL } from 'mailing-core';
import { MjmlSection, MjmlWrapper, MjmlColumn, MjmlText } from 'mjml-react';
import React from 'react';

import { colors, fontSize, fontWeight } from '../theme';
import Link from './link';

type FooterProps = {
includeUnsubscribe?: boolean;
};

export default function Footer({ includeUnsubscribe = true }: FooterProps) {
return (
<MjmlWrapper paddingTop={32}>
<MjmlSection
borderTop={`1px solid ${colors.gray[700]}`}
paddingTop={32}
paddingBottom={24}
>
<MjmlColumn>
<MjmlText
align="left"
fontSize={fontSize.xs}
fontWeight={fontWeight.bold}
>
{`Copyright © ${new Date().getFullYear()} Chirpy`}
{includeUnsubscribe && (
<>
{` - `}
<Link
color={colors.gray[900]}
href={EMAIL_PREFERENCES_URL}
textDecoration="none"
fontSize="font-weight: normal"
>
Unsubscribe
</Link>
</>
)}
</MjmlText>
</MjmlColumn>
</MjmlSection>
</MjmlWrapper>
);
}
38 changes: 38 additions & 0 deletions apps/main/emails/components/header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { MjmlColumn, MjmlGroup, MjmlSection, MjmlWrapper } from 'mjml-react';
import React from 'react';

import { fontSize, fontWeight } from '../theme';
import Link from './link';
import Text from './text';

export default function Header() {
return (
<MjmlWrapper padding="40px 0 64px">
<MjmlSection>
<MjmlGroup>
<MjmlColumn width="42%">
<Text align="left">
<Link
fontSize={fontSize.xl}
fontWeight={fontWeight.bold}
href="https://mailing.run"
textDecoration="none"
>
<img
width="100"
src={'https://chirpy.dev/images/logo.png'}
alt=""
style={{
verticalAlign: 'text-bottom',
paddingRight: 10,
paddingBottom: 2,
}}
/>
</Link>
</Text>
</MjmlColumn>
</MjmlGroup>
</MjmlSection>
</MjmlWrapper>
);
}
21 changes: 21 additions & 0 deletions apps/main/emails/components/heading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from 'react';

import { fontFamily, lineHeight, fontWeight, fontSize } from '../theme';
import Text from './text';

type HeadingProps = React.ComponentProps<typeof Text>;

const defaultProps = {
fontFamily: fontFamily.sans,
fontWeight: fontWeight.semibold,
lineHeight: lineHeight.tight,
fontSize: fontSize.lg,
};

export default function Heading(props: HeadingProps) {
return (
<Text {...defaultProps} {...props}>
{props.children}
</Text>
);
}
Loading

0 comments on commit 01288c3

Please sign in to comment.