Skip to content

Commit

Permalink
Added menu bar for smaller screens and updated some spacing (#4)
Browse files Browse the repository at this point in the history
* Added menu bar for smaller screens and updated some spacing
* Clarify how to add a notification destination
* Fixed links to tutorial

---------

Co-authored-by: heymcgovern <25659933+heymcgovern@users.noreply.github.com>
  • Loading branch information
vijayasingam-paddle and heymcgovern authored Sep 18, 2024
1 parent bdcb0b9 commit fa2315b
Show file tree
Hide file tree
Showing 14 changed files with 73 additions and 36 deletions.
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,15 @@ This starter kit is built with:

## Step-by-step setup

> **Important:** If you're totally new to Next.js and Paddle, we have a more complete tutorial on our dev docs: [Build and deploy Next.js app with Vercel and Supabase](https://developer.paddle.com/build/vercel-starter-kit?utm_source=dx&utm_medium=paddle-nextjs-starter-kit)
> **Important:** If you're totally new to Next.js and Paddle, we have a more complete tutorial on our dev docs: [Build and deploy Next.js app with Vercel and Supabase](https://developer.paddle.com/build/nextjs-supabase-vercel-starter-kit?utm_source=dx&utm_medium=paddle-nextjs-starter-kit)
### 1. Deploy on Vercel

#### Start deploy

Click this button to clone this repo and create a new project in your Vercel account:

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FPaddleHQ%2Fpaddle-nextjs-starter-kit&env=PADDLE_API_KEY,PADDLE_NOTIFICATION_WEBHOOK_SECRET,NEXT_PUBLIC_PADDLE_ENV,NEXT_PUBLIC_PADDLE_CLIENT_TOKEN&integration-ids=oac_VqOgBHqhEoFTPzGkPd7L0iH6)
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FPaddleHQ%2Fpaddle-nextjs-starter-kit&env=PADDLE_API_KEY,PADDLE_NOTIFICATION_WEBHOOK_SECRET,NEXT_PUBLIC_PADDLE_ENV,NEXT_PUBLIC_PADDLE_CLIENT_TOKEN&integration-ids=oac_VqOgBHqhEoFTPzGkPd7L0iH6&external-id=https%3A%2F%2Fgithub.com%2FPaddleHQ%2Fpaddle-nextjs-starter-kit%2Ftree%2Fmain)

You can also [create a new application manually](https://vercel.com/new).

Expand All @@ -63,12 +63,12 @@ Click **Add** to walk through integrating with Supabase. You'll be asked to auth

Then, enter Paddle environment variables:

| Variable | Used for | How to get it |
| ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `PADDLE_API_KEY` | An [API key](https://developer.paddle.com/api-reference/about/authentication?utm_source=dx&utm_medium=paddle-nextjs-starter-kit), used for interacting with Paddle data in the backend. For example, syncing customer and subscription data with Supabase. | Go to [**Paddle > Developer tools > Authentication**](https://sandbox-vendors.paddle.com/authentication-v2) and create a new API key. |
| `NEXT_PUBLIC_PADDLE_CLIENT_TOKEN` | A [client-side key](https://developer.paddle.com/api-reference/about/authentication?utm_source=dx&utm_medium=paddle-nextjs-starter-kit), used for interacting with Paddle in the frontend. For example, getting localized prices for pricing pages and opening a checkout. | Go to [**Paddle > Developer tools > Authentication**](https://sandbox-vendors.paddle.com/authentication-v2) and create a new client-side token. |
| `PADDLE_NOTIFICATION_WEBHOOK_SECRET` | A secret key used for verifying that [webhooks](https://developer.paddle.com/webhooks/notification-destinations?utm_source=dx&utm_medium=paddle-nextjs-starter-kit) came from Paddle and haven't been tampered with in transit. Important for security. | Go to [**Paddle > Developer tools > Notifications**](https://sandbox-vendors.paddle.com/notifications), create a new notification destination, then edit to copy the secret key. |
| `NEXT_PUBLIC_PADDLE_ENV` | Environment for our Paddle account. This should match the kind of Paddle account you signed up for. | Enter `sandbox` for sandbox accounts or `production` for live accounts. |
| Variable | Used for | How to get it |
| ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `PADDLE_API_KEY` | An [API key](https://developer.paddle.com/api-reference/about/authentication?utm_source=dx&utm_medium=paddle-nextjs-starter-kit), used for interacting with Paddle data in the backend. For example, syncing customer and subscription data with Supabase. | Go to [**Paddle > Developer tools > Authentication**](https://sandbox-vendors.paddle.com/authentication-v2) and create a new API key. |
| `NEXT_PUBLIC_PADDLE_CLIENT_TOKEN` | A [client-side key](https://developer.paddle.com/api-reference/about/authentication?utm_source=dx&utm_medium=paddle-nextjs-starter-kit), used for interacting with Paddle in the frontend. For example, getting localized prices for pricing pages and opening a checkout. | Go to [**Paddle > Developer tools > Authentication**](https://sandbox-vendors.paddle.com/authentication-v2) and create a new client-side token. |
| `PADDLE_NOTIFICATION_WEBHOOK_SECRET` | A secret key used for verifying that [webhooks](https://developer.paddle.com/webhooks/notification-destinations?utm_source=dx&utm_medium=paddle-nextjs-starter-kit) came from Paddle and haven't been tampered with in transit. Important for security. | Go to [**Paddle > Developer tools > Notifications**](https://sandbox-vendors.paddle.com/notifications), create a new notification destination for `https://<PROJECTNAME>.vercel.app/api/webhook`, then edit to copy the secret key. |
| `NEXT_PUBLIC_PADDLE_ENV` | Environment for our Paddle account. This should match the kind of Paddle account you signed up for. | Enter `sandbox` for sandbox accounts or `production` for live accounts. |

You can use `https://<PROJECTNAME>.vercel.app/api/webhook` as the endpoint URL for your notification destination, where `<PROJECTNAME>` is the name of your project in Vercel. This may change if your project name isn't unique, but we can update this later.

Expand Down Expand Up @@ -163,6 +163,6 @@ For help, contact the Paddle DX team at `team-dx@paddle.com`.

## Learn more

- [Build and deploy Next.js app with Vercel and Supabase](https://developer.paddle.com/build/vercel-starter-kit?utm_source=dx&utm_medium=paddle-nextjs-starter-kit)
- [Build and deploy Next.js app with Vercel and Supabase](https://developer.paddle.com/build/nextjs-supabase-vercel-starter-kit?utm_source=dx&utm_medium=paddle-nextjs-starter-kit)
- [Paddle API reference](https://developer.paddle.com/api-reference/overview?utm_source=dx&utm_medium=paddle-nextjs-starter-kit)
- [Sign up for Paddle Billing](https://sandbox-login.paddle.com/signup?utm_source=dx&utm_medium=paddle-nextjs-starter-kit)
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@ export async function DashboardSubscriptionCardGroup() {
</Button>
</CardTitle>
</CardHeader>
<CardContent className={'p-0 pt-6'}>
<CardContent className={'p-0 pt-6 @container'}>
{subscriptions?.data ? (
<SubscriptionCards className={'grid-cols-2 gap-6'} subscriptions={subscriptions.data.slice(0, 2) ?? []} />
<SubscriptionCards
className={'grid-cols-1 gap-6 @[600px]:grid-cols-2'}
subscriptions={subscriptions.data.slice(0, 2) ?? []}
/>
) : (
<ErrorContent />
)}
Expand Down
4 changes: 2 additions & 2 deletions src/components/dashboard/landing/dashboard-landing-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import { DashboardTeamMembersCard } from '@/components/dashboard/landing/compone
export function DashboardLandingPage() {
return (
<div className={'grid flex-1 items-start gap-6 p-0 md:grid-cols-1 lg:grid-cols-2 xl:grid-cols-3'}>
<div className={'grid auto-rows-max items-start gap-8 lg:col-span-2'}>
<div className={'grid auto-rows-max items-start gap-6 lg:col-span-2'}>
<DashboardUsageCardGroup />
<DashboardSubscriptionCardGroup />
</div>
<div className={'grid auto-rows-max items-start gap-8'}>
<div className={'grid auto-rows-max items-start gap-6'}>
<DashboardTeamMembersCard />
<DashboardTutorialCard />
</div>
Expand Down
6 changes: 5 additions & 1 deletion src/components/dashboard/layout/dashboard-page-header.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Separator } from '@/components/ui/separator';
import { MobileSidebar } from '@/components/dashboard/layout/mobile-sidebar';

interface Props {
pageTitle: string;
Expand All @@ -7,7 +8,10 @@ interface Props {
export function DashboardPageHeader({ pageTitle }: Props) {
return (
<div>
<h1 className="text-lg font-semibold md:text-4xl">{pageTitle}</h1>
<div className={'flex items-center gap-6'}>
<MobileSidebar />
<h1 className="text-lg font-semibold md:text-4xl">{pageTitle}</h1>
</div>
<Separator className={'relative bg-border my-8 dashboard-header-highlight'} />
</div>
);
Expand Down
22 changes: 22 additions & 0 deletions src/components/dashboard/layout/mobile-sidebar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Sheet, SheetContent, SheetTrigger } from '@/components/ui/sheet';
import { Button } from '@/components/ui/button';
import { Menu } from 'lucide-react';
import { Sidebar } from '@/components/dashboard/layout/sidebar';
import { SidebarUserInfo } from '@/components/dashboard/layout/sidebar-user-info';

export function MobileSidebar() {
return (
<Sheet>
<SheetTrigger asChild>
<Button variant="ghost" size="icon" className="shrink-0 md:hidden">
<Menu className="h-5 w-5" />
<span className="sr-only">Toggle navigation menu</span>
</Button>
</SheetTrigger>
<SheetContent side="left" className="flex flex-col">
<Sidebar />
<SidebarUserInfo />
</SheetContent>
</Sheet>
);
}
14 changes: 8 additions & 6 deletions src/components/dashboard/payments/components/columns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,14 @@ export const columns: ColumnDef<Transaction>[] = [
size: columnSize,
cell: ({ row }) => {
return (
<div className={'whitespace-nowrap flex gap-1'}>
<span className={'font-semibold'}>{getPaymentReason(row.original.origin)}</span>
<span className={'font-medium'}>{row.original.details?.lineItems[0].product?.name}</span>
{row.original.details?.lineItems && row.original.details?.lineItems.length > 1 && (
<span className={'font-medium'}>+{row.original.details?.lineItems.length - 1} more</span>
)}
<div className={'max-w-[250px]'}>
<div className={'whitespace-nowrap flex gap-1 truncate'}>
<span className={'font-semibold'}>{getPaymentReason(row.original.origin)}</span>
<span className={'font-medium truncate'}>{row.original.details?.lineItems[0].product?.name}</span>
{row.original.details?.lineItems && row.original.details?.lineItems.length > 1 && (
<span className={'font-medium'}>+{row.original.details?.lineItems.length - 1} more</span>
)}
</div>
</div>
);
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export function PaymentMethodSection({ transactions, updatePaymentMethodUrl }: P
return null;
}
return (
<div className={'flex gap-6 pt-6 items-end justify-between'}>
<div className={'flex gap-6 pt-6 items-end justify-between @16xs:flex-wrap'}>
<div className={'flex flex-col gap-4'}>
<div className={'text-base text-secondary leading-4 whitespace-nowrap'}>Payment method</div>
<div className={'flex gap-1 items-end'}>
Expand All @@ -31,7 +31,7 @@ export function PaymentMethodSection({ transactions, updatePaymentMethodUrl }: P
<div>
<Button asChild={true} size={'sm'} className={'text-sm rounded-sm border-border'} variant={'outline'}>
<Link target={'_blank'} href={updatePaymentMethodUrl}>
Manage
Update
</Link>
</Button>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export function SubscriptionCards({ subscriptions, className }: Props) {
{subscriptions.map((subscription) => {
const subscriptionItem = subscription.items[0];
const price = subscriptionItem.quantity * parseFloat(subscriptionItem.price.unitPrice.amount);
const formattedPrice = parseMoney(price.toString(), subscriptionItem.price.unitPrice.currencyCode);
const formattedPrice = parseMoney(price.toString(), subscription.currencyCode);
const frequency =
subscription.billingCycle.frequency === 1
? `/${subscription.billingCycle.interval}`
Expand All @@ -30,7 +30,12 @@ export function SubscriptionCards({ subscriptions, className }: Props) {
<Card key={subscription.id} className={'bg-background/50 backdrop-blur-[24px] border-border p-6'}>
<CardHeader className="p-0 space-y-0">
<CardTitle className="flex flex-col justify-between items-start mb-6">
<div className={'flex mb-4 justify-between w-full'}>
<div
className={cn('flex mb-4 w-full', {
'justify-between': subscriptionItem.product.imageUrl,
'justify-end': !subscriptionItem.product.imageUrl,
})}
>
{subscriptionItem.product.imageUrl && (
<Image
src={subscriptionItem.product.imageUrl}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,12 @@ export function SubscriptionDetail({ subscriptionId }: Props) {
<SubscriptionHeader subscription={subscription.data} />
<Separator className={'relative bg-border mb-8 dashboard-header-highlight'} />
</div>
<div className={'grid flex-1 items-start gap-8 xl:grid-cols-4'}>
<div className={'grid auto-rows-max items-start gap-8'}>
<div className={'grid gap-6 grid-cols-1 xl:grid-cols-6'}>
<div className={'grid auto-rows-max gap-6 grid-cols-1 xl:col-span-2'}>
<SubscriptionNextPaymentCard transactions={transactions.data} subscription={subscription.data} />
<SubscriptionPastPaymentsCard transactions={transactions.data} subscriptionId={subscriptionId} />
</div>
<div className={'grid auto-rows-max items-start gap-8 xl:col-span-3'}>
<div className={'grid auto-rows-max gap-6 grid-cols-1 xl:col-span-4'}>
<SubscriptionLineItems subscription={subscription.data} />
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { Status } from '@/components/shared/status/status';
import { parseMoney } from '@/utils/paddle/parse-money';
import dayjs from 'dayjs';
import { SubscriptionHeaderActionButton } from '@/components/dashboard/subscriptions/components/subscription-header-action-button';
import { Alert } from '@/components/ui/alert';
import { SubscriptionAlerts } from '@/components/dashboard/subscriptions/components/subscription-alerts';
import { MobileSidebar } from '@/components/dashboard/layout/mobile-sidebar';

interface Props {
subscription: Subscription;
Expand All @@ -24,16 +24,17 @@ export function SubscriptionHeader({ subscription }: Props) {
const formattedStartedDate = dayjs(subscription.startedAt).format('MMM DD, YYYY');

return (
<div className={'flex justify-between items-center'}>
<div className={'flex justify-between items-start sm:items-center flex-col sm:flex-row mb-6 sm:mb-0'}>
<div className={'flex flex-col w-full'}>
<SubscriptionAlerts subscription={subscription} />
<div className={'flex items-center gap-5'}>
<MobileSidebar />
{subscriptionItem.product.imageUrl && (
<Image src={subscriptionItem.product.imageUrl} alt={subscriptionItem.product.name} width={48} height={48} />
)}
<span className={'text-4xl leading-9 font-medium'}>{subscriptionItem.product.name}</span>
</div>
<div className={'flex items-center gap-8 py-8 pb-6'}>
<div className={'flex items-center gap-6 py-8 pb-6 flex-wrap md:flex-wrap'}>
<div className={'flex gap-1 items-end'}>
<span className={'text-4xl leading-9 font-medium'}>{formattedPrice}</span>
<span className={'text-secondary text-sm leading-[14px] font-medium'}>{frequency}</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ export function SubscriptionNextPaymentCard({ subscription, transactions }: Prop
return null;
}
return (
<Card className={'bg-background/50 backdrop-blur-[24px] border-border p-6'}>
<Card className={'bg-background/50 backdrop-blur-[24px] border-border p-6 @container'}>
<div className={'flex gap-6 flex-col border-border border-b pb-6'}>
<div className={'text-xl font-medium'}>Next payment</div>
<div className={'flex gap-1 items-end'}>
<div className={'flex gap-1 items-end @16xs:flex-wrap'}>
<span className={'text-xl leading-5 font-medium text-primary'}>
{parseMoney(subscription?.nextTransaction?.details.totals.total, subscription?.currencyCode)}
</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export function MultipleSubscriptionsView({ subscriptions }: Props) {
return (
<>
<DashboardPageHeader pageTitle={'Subscriptions'} />
<SubscriptionCards className={'grid-cols-1 lg:grid-cols-3 gap-8'} subscriptions={subscriptions} />
<SubscriptionCards className={'grid-cols-1 lg:grid-cols-3 gap-6'} subscriptions={subscriptions} />
</>
);
}
2 changes: 1 addition & 1 deletion src/components/home/footer/powered-by-paddle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export function PoweredByPaddle() {
<span className={'text-sm leading-[14px]'}>A Next.js template by</span>
<Image src={'/assets/icons/logo/paddle-white-logo.svg'} alt={'Paddle logo'} width={54} height={14} />
</div>
<div className={'flex justify-center items-center gap-2'}>
<div className={'flex justify-center items-center gap-2 flex-wrap md:flex-nowrap'}>
<Link className={'text-sm leading-[14px]'} href={'https://paddle.com'} target={'_blank'}>
<span className={'flex items-center gap-1'}>
Explore Paddle
Expand Down
Loading

0 comments on commit fa2315b

Please sign in to comment.