-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
07bacc2
commit 6850439
Showing
9 changed files
with
685 additions
and
6 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
'use server' | ||
|
||
import { Client } from '@notionhq/client' | ||
import { CreatePageParameters } from '@notionhq/client/build/src/api-endpoints' | ||
|
||
export type NotionRecord = { | ||
yourName: string | ||
email?: string | ||
twitter?: string | ||
productName?: string | ||
productType?: string[] | ||
productUrl?: string | ||
productDescription?: string | ||
} | ||
|
||
export async function addRecordToNotion(record: NotionRecord) { | ||
const notion = new Client({ | ||
auth: process.env.NOTION_KEY | ||
}) | ||
|
||
const databaseId = process.env.NOTION_PODAPPS_DBID | ||
|
||
const types = [] | ||
if(record.productType?.includes("webapp")) { | ||
types.push("Web app") | ||
} | ||
if(record.productType?.includes("mobileapp")) { | ||
types.push("Mobile app") | ||
} | ||
if(record.productType?.includes("desktopapp")) { | ||
types.push("Desktop app") | ||
} | ||
if(record.productType?.includes("devtools")) { | ||
types.push("Dev tools") | ||
} | ||
|
||
const props: CreatePageParameters = { | ||
parent: { | ||
database_id: databaseId as string | ||
}, | ||
properties: { | ||
"Name": { | ||
title: [ | ||
{ | ||
text: { | ||
content: record.yourName as string | ||
} | ||
} | ||
] | ||
}, | ||
} | ||
} | ||
|
||
if(record.email) { | ||
props.properties["Email"] = { | ||
email: record.email | ||
} | ||
} | ||
|
||
if (record.twitter) { | ||
props.properties["Twitter"] = { | ||
rich_text: [ | ||
{ | ||
text: { | ||
content: record.twitter | ||
} | ||
} | ||
] | ||
} | ||
} | ||
|
||
if (record.productName) { | ||
props.properties["Product name"] = { | ||
rich_text: [ | ||
{ | ||
text: { | ||
content: record.productName | ||
} | ||
} | ||
] | ||
} | ||
} | ||
|
||
if (record.productDescription) { | ||
props.properties["Product description"] = { | ||
rich_text: [ | ||
{ | ||
text: { | ||
content: record.productDescription | ||
} | ||
} | ||
] | ||
} | ||
} | ||
|
||
if (record.productUrl) { | ||
props.properties["Product URL"] = { | ||
url: record.productUrl | ||
} | ||
} | ||
|
||
if (types.length > 0) { | ||
props.properties["Product type"] = { | ||
multi_select: types.map(type => ({ name: type })) | ||
} | ||
} | ||
|
||
|
||
let res = await notion.pages.create(props) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
'use client' | ||
import { Input } from '@/components/ui/input' | ||
import { Label } from '@/components/ui/label' | ||
import React, { FormEvent, useState } from 'react' | ||
import { NotionRecord, addRecordToNotion } from './actions' | ||
import { Button } from '@/components/ui/button' | ||
import { Checkbox } from '@/components/ui/checkbox' | ||
import { RadioGroup, RadioGroupItem } from '@radix-ui/react-radio-group' | ||
import { Textarea } from '@/components/ui/textarea' | ||
import toast from 'react-hot-toast' | ||
import { useRouter } from 'next/navigation' | ||
|
||
function Page() { | ||
const router = useRouter() | ||
|
||
const [isLoading, setIsLoading] = useState(false) | ||
|
||
async function onSubmit(event: FormEvent<HTMLFormElement>) { | ||
event.preventDefault() | ||
try { | ||
setIsLoading(true) | ||
const formData = new FormData(event.currentTarget) | ||
let data: NotionRecord = { | ||
yourName: formData.get('name') as string, | ||
email: formData.get('email') as string, | ||
twitter: formData.get('twitter') as string, | ||
productName: formData.get('productName') as string, | ||
productUrl: formData.get('productUrl') as string, | ||
productType: ['webapp', 'mobileapp', 'desktopapp', 'devtools'].filter((type) => formData.get(type) === 'on'), | ||
productDescription: formData.get('productDescription') as string, | ||
} | ||
await addRecordToNotion(data) | ||
router.push('/podcast/apply/success') | ||
} catch(err) { | ||
console.error(err) | ||
toast.error("Something went wrong! Reach out to @brianmmdev on Twitter for help.") | ||
} finally { | ||
setIsLoading(false) | ||
} | ||
} | ||
|
||
return ( | ||
<section className="space-y-8"> | ||
<header className="flex flex-col gap-2"> | ||
<h1>Apply to be on the podcast</h1> | ||
<p className="lg:text-lg text-balance md:max-w-prose"> | ||
The goal of the fullstack.chat podcast is to share the stories of developers building amazing web, desktop, or mobile applications. We want to hear about your journey, the challenges you've faced, and the lessons you've learned along the way. | ||
</p> | ||
</header> | ||
|
||
<form onSubmit={onSubmit} className='flex flex-col gap-2' > | ||
<div className="grid w-full max-w-sm items-center gap-1.5"> | ||
<Label htmlFor="name">Your full name</Label> | ||
<Input type="text" id="name" name="name" placeholder="Your full name" disabled={isLoading} /> | ||
</div> | ||
<div className="grid w-full max-w-sm items-center gap-1.5"> | ||
<Label htmlFor="email">Email</Label> | ||
<Input type="email" id="email" name="email" placeholder="Email" disabled={isLoading} /> | ||
</div> | ||
<div className="grid w-full max-w-sm items-center gap-1.5"> | ||
<Label htmlFor="twitter">Twitter/X handle</Label> | ||
<Input type="text" id="twitter" name="twitter" placeholder="@fullstackchat" disabled={isLoading} /> | ||
</div> | ||
<div className="grid w-full max-w-sm items-center gap-1.5"> | ||
<Label className="mb-1">Type of product</Label> | ||
<div className="items-top flex space-x-2"> | ||
<Checkbox disabled={isLoading} id="webapp" name='webapp' /> | ||
<div className="grid gap-1.5 leading-none"> | ||
<Label htmlFor="webapp" className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" > | ||
Web | ||
</Label> | ||
</div> | ||
</div> | ||
<div className="items-top flex space-x-2"> | ||
<Checkbox disabled={isLoading} id="mobileapp" name='mobileapp' /> | ||
<div className="grid gap-1.5 leading-none"> | ||
<Label htmlFor="mobileapp" className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" > | ||
Mobile | ||
</Label> | ||
</div> | ||
</div> | ||
<div className="items-top flex space-x-2"> | ||
<Checkbox disabled={isLoading} id="desktopapp" name='desktopapp' /> | ||
<div className="grid gap-1.5 leading-none"> | ||
<Label htmlFor="desktopapp" className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" > | ||
Desktop | ||
</Label> | ||
</div> | ||
</div> | ||
<div className="items-top flex space-x-2"> | ||
<Checkbox disabled={isLoading} id="devtools" name='devtools' /> | ||
<div className="grid gap-1.5 leading-none"> | ||
<Label htmlFor="devtools" className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" > | ||
Dev tools | ||
</Label> | ||
</div> | ||
</div> | ||
</div> | ||
|
||
<div className="grid w-full max-w-sm items-center gap-1.5"> | ||
<Label htmlFor="productName">Product name</Label> | ||
<Input type="text" id="productName" name="productName" placeholder="Product name" disabled={isLoading} /> | ||
</div> | ||
|
||
<div className="grid w-full max-w-sm items-center gap-1.5"> | ||
<Label htmlFor="productUrl">Product URL</Label> | ||
<Input type="text" id="productUrl" name="productUrl" placeholder="Product URL" disabled={isLoading} /> | ||
</div> | ||
|
||
{/* <div className="grid w-full max-w-sm items-center gap-1.5"> | ||
<RadioGroup defaultValue="planning" name='phase'> | ||
<div className="flex items-center space-x-2"> | ||
<RadioGroupItem value="planning" id="planning" /> | ||
<Label htmlFor="planning">Planing</Label> | ||
</div> | ||
<div className="flex items-center space-x-2"> | ||
<RadioGroupItem value="indev" id="indev" /> | ||
<Label htmlFor="indev">In development</Label> | ||
</div> | ||
<div className="flex items-center space-x-2"> | ||
<RadioGroupItem value="launched" id="launched" /> | ||
<Label htmlFor="launched">Launched</Label> | ||
</div> | ||
</RadioGroup> | ||
</div> */} | ||
|
||
{/* <div className="grid w-full max-w-sm items-center gap-1.5"> | ||
tech used (make this a multiselect and save to tags) | ||
</div> */} | ||
|
||
<div className="grid w-full max-w-sm items-center gap-1.5"> | ||
<Label htmlFor="productDescription">Product description</Label> | ||
<Textarea placeholder="Product description" id="productDescription" name="productDescription" disabled={isLoading} /> | ||
<p className="text-sm text-muted-foreground"> | ||
What does your product do? What problem does it solve? | ||
</p> | ||
|
||
</div> | ||
|
||
<div className='flex'> | ||
<Button type='submit' disabled={isLoading}> | ||
{ isLoading ? 'Submitting...' : 'Submit'} | ||
</Button> | ||
</div> | ||
</form> | ||
</section> | ||
) | ||
} | ||
|
||
export default Page |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import JoinButton from '@/app/lib/components/JoinButton' | ||
import React from 'react' | ||
|
||
function Page() { | ||
return ( | ||
|
||
<header className="flex flex-col gap-2"> | ||
<h1>Thanks for applying!</h1> | ||
<p className="lg:text-lg text-balance md:max-w-prose"> | ||
If we feel you're a good fit for the show, we'll reach out to schedule! In the meantime, join the Discord if you aren't already a member and introduce yourself! | ||
</p> | ||
<div className='flex'> | ||
<JoinButton /> | ||
</div> | ||
</header> | ||
) | ||
} | ||
|
||
export default Page |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
"use client" | ||
|
||
import * as React from "react" | ||
import * as CheckboxPrimitive from "@radix-ui/react-checkbox" | ||
import { Check } from "lucide-react" | ||
|
||
import { cn } from "@/lib/utils" | ||
|
||
const Checkbox = React.forwardRef< | ||
React.ElementRef<typeof CheckboxPrimitive.Root>, | ||
React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root> | ||
>(({ className, ...props }, ref) => ( | ||
<CheckboxPrimitive.Root | ||
ref={ref} | ||
className={cn( | ||
"peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground", | ||
className | ||
)} | ||
{...props} | ||
> | ||
<CheckboxPrimitive.Indicator | ||
className={cn("flex items-center justify-center text-current")} | ||
> | ||
<Check className="h-4 w-4" /> | ||
</CheckboxPrimitive.Indicator> | ||
</CheckboxPrimitive.Root> | ||
)) | ||
Checkbox.displayName = CheckboxPrimitive.Root.displayName | ||
|
||
export { Checkbox } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
"use client" | ||
|
||
import * as React from "react" | ||
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group" | ||
import { Circle } from "lucide-react" | ||
|
||
import { cn } from "@/lib/utils" | ||
|
||
const RadioGroup = React.forwardRef< | ||
React.ElementRef<typeof RadioGroupPrimitive.Root>, | ||
React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root> | ||
>(({ className, ...props }, ref) => { | ||
return ( | ||
<RadioGroupPrimitive.Root | ||
className={cn("grid gap-2", className)} | ||
{...props} | ||
ref={ref} | ||
/> | ||
) | ||
}) | ||
RadioGroup.displayName = RadioGroupPrimitive.Root.displayName | ||
|
||
const RadioGroupItem = React.forwardRef< | ||
React.ElementRef<typeof RadioGroupPrimitive.Item>, | ||
React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item> | ||
>(({ className, ...props }, ref) => { | ||
return ( | ||
<RadioGroupPrimitive.Item | ||
ref={ref} | ||
className={cn( | ||
"aspect-square h-4 w-4 rounded-full border border-primary text-primary ring-offset-background focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50", | ||
className | ||
)} | ||
{...props} | ||
> | ||
<RadioGroupPrimitive.Indicator className="flex items-center justify-center"> | ||
<Circle className="h-2.5 w-2.5 fill-current text-current" /> | ||
</RadioGroupPrimitive.Indicator> | ||
</RadioGroupPrimitive.Item> | ||
) | ||
}) | ||
RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName | ||
|
||
export { RadioGroup, RadioGroupItem } |