Skip to content

Commit

Permalink
Merge branch 'canary' into 10-11-refactor-stats
Browse files Browse the repository at this point in the history
  • Loading branch information
feedthejim committed Oct 12, 2023
2 parents a542d5a + c1a1583 commit 0944fdd
Show file tree
Hide file tree
Showing 53 changed files with 442 additions and 560 deletions.
2 changes: 1 addition & 1 deletion errors/large-page-data.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Reduce the amount of data returned from `getStaticProps`, `getServerSideProps`,
To inspect the props passed to your page, you can inspect the below element's content in your browser devtools:

```bash filename="Terminal"
document.getElementById("__NEXT_DATA__").text
JSON.parse(document.getElementById("__NEXT_DATA__").textContent)
```

## Useful Links
Expand Down
21 changes: 6 additions & 15 deletions examples/with-fauna/README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
# Fauna GraphQL Guestbook Starter
# Fauna Guestbook Starter

This Guestbook Single-Page Application (SPA) example shows you how to use [Fauna's GraphQL endpoint](https://docs.fauna.com/fauna/current/api/graphql/) in your Next.js project.
This Guestbook Application example shows you how to use [Fauna](https://docs.fauna.com/) in your Next.js project.

## Deploy your own

Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example):

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/vercel/next.js/tree/canary/examples/with-fauna&project-name=fauna-nextjs-guestbook&repository-name=fauna-nextjs-guestbook&demo-title=Next.js%20Fauna%20Guestbook%20App&demo-description=A%20simple%20guestbook%20application%20built%20with%20Next.js%20and%20Fauna&integration-ids=oac_Erlbqm8Teb1y4WhioE3r2utY)

## Why Fauna

By importing a `.gql` or `.graphql` schema into Fauna ([see our sample schema file](./schema.gql)), Fauna will generate required Indexes and GraphQL resolvers for you -- hands free 👐 ([some limitations exist](https://docs.fauna.com/fauna/current/api/graphql/#limitations)).

## How to use

Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init), [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/), or [pnpm](https://pnpm.io) to bootstrap the example:
Expand All @@ -26,17 +22,12 @@ pnpm create next-app --example with-fauna with-fauna-app

You can start with this template [using `create-next-app`](#using-create-next-app) or by [downloading the repository manually](#download-manually).

To use a live Fauna database, create a database at [dashboard.fauna.com](https://dashboard.fauna.com/) and generate an admin token by going to the **Security** tab on the left and then click **New Key**. Give the new key a name and select the 'Admin' Role. Copy the token since the setup script will ask for it. Do not use it in the frontend, it has superpowers which you don't want to give to your users.

### Setting Up Your Schema

The Next.js and Fauna example includes a setup script (`npm run setup`). After providing your admin token, the script will:
### Setting Up Your Fauna Database

- **Import your GraphQL schema:** Fauna automatically sets up collections and indexes to support your queries. You can view these in your [project dashboard](https://dashboard.fauna.com/) under **GraphQL**.
- **Create an index and function:** The script will create a GraphQL resolver that uses [User-defined functions](https://docs.fauna.com/fauna/current/api/graphql/functions?lang=javascript) based on a sorting index.
- **Create a scoped token:** This token is for use on the client side. The admin key can be used on the server side.
Head over to [Fauna Dashboard](https://dashboard.fauna.com/) and create a new database. You can name it whatever you want, but for this example, we'll use `nextjs-guestbook`. Next, create a new collection called `Entry` in your new database.
Finally create a new database access key to connect to your database.

After the script completes, a `.env.local` [file](https://nextjs.org/docs/basic-features/environment-variables) will be created for you with the newly generated client token assigned to an Environment Variable.
Watch [this video](https://www.youtube.com/watch?v=8YJcG2fUPyE&t=43s&ab_channel=FaunaInc.) to learn how to connect to your database.

### Run locally

Expand Down
22 changes: 22 additions & 0 deletions examples/with-fauna/actions/entry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
'use server'

import { revalidatePath } from 'next/cache'
import { createEntry } from '@/lib/fauna'

export async function createEntryAction(prevState: any, formData: FormData) {
const name = formData.get('name') as string
const message = formData.get('message') as string
try {
await createEntry(name, message)
revalidatePath('/')
return {
successMessage: 'Thank you for signing the guest book',
errorMessage: null,
}
} catch (error) {
return {
successMessage: null,
errorMessage: 'Something went wrong. Please try again',
}
}
}
3 changes: 3 additions & 0 deletions examples/with-fauna/app/globals.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
52 changes: 52 additions & 0 deletions examples/with-fauna/app/guestbook-page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import cn from 'classnames'
import formatDate from 'date-fns/format'
import EntryForm from '@/components/EntryForm'
import { EntryType } from './page'

const EntryItem = ({ entry }: { entry: EntryType }) => (
<div className="flex flex-col space-y-2">
<div className="prose dark:prose-dark w-full">{entry.message}</div>
<div className="flex items-center space-x-3">
<p className="text-sm text-gray-500">{entry.name}</p>
<span className="text-gray-200 dark:text-gray-800">/</span>
<p className="text-sm text-gray-400 dark:text-gray-600">
{formatDate(
new Date(entry.createdAt.isoString),
"d MMM yyyy 'at' h:mm bb"
)}
</p>
</div>
</div>
)

export default async function GuestbookPage({
entries,
}: {
entries: EntryType[]
}) {
return (
<main className="max-w-4xl mx-auto p-4">
<div
className={cn(
'border border-blue-200 rounded p-6',
'my-4 w-full dark:border-gray-800 bg-blue-50',
'dark:bg-blue-opaque'
)}
>
<h5 className={cn('text-lg md:text-xl font-bold', 'text-gray-900')}>
Sign the Guestbook
</h5>
<p className="my-1 text-gray-800">
Share a message for a future visitor.
</p>
<EntryForm />
</div>

<div className="mt-4 space-y-8 px-2">
{entries?.map((entry) => (
<EntryItem key={entry.id} entry={entry} />
))}
</div>
</main>
)
}
21 changes: 21 additions & 0 deletions examples/with-fauna/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import './globals.css'

export const metadata: {
title: string
description: string
} = {
title: 'Next.js + Fauna example',
description: 'Generated by Next.js',
}

export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}
16 changes: 16 additions & 0 deletions examples/with-fauna/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { getAllEntries } from '@/lib/fauna'
import GuestbookPage from './guestbook-page'

export type EntryType = {
id: string
name: string
message: string
createdAt: {
isoString: string
}
}

export default async function Page() {
const entries = (await getAllEntries()) as EntryType[]
return <GuestbookPage entries={entries} />
}
65 changes: 65 additions & 0 deletions examples/with-fauna/components/EntryForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
'use client'

import cn from 'classnames'
import { createEntryAction } from '@/actions/entry'
// @ts-ignore
import { experimental_useFormState as useFormState } from 'react-dom'
import { experimental_useFormStatus as useFormStatus } from 'react-dom'
import LoadingSpinner from '@/components/LoadingSpinner'
import SuccessMessage from '@/components/SuccessMessage'
import ErrorMessage from '@/components/ErrorMessage'

const inputClasses = cn(
'block py-2 bg-white dark:bg-gray-800',
'rounded-md border-gray-300 focus:ring-blue-500',
'focus:border-blue-500 text-gray-900 dark:text-gray-100'
)

const initialState = {
successMessage: null,
errorMessage: null,
}

export default function EntryForm() {
const [state, formAction] = useFormState(createEntryAction, initialState)
const { pending } = useFormStatus()

return (
<>
<form className="flex relative my-4" action={formAction}>
<input
required
className={cn(inputClasses, 'w-1/3 mr-2 px-4')}
aria-label="Your name"
placeholder="Your name..."
name="name"
/>
<input
required
className={cn(inputClasses, 'pl-4 pr-32 flex-grow')}
aria-label="Your message"
placeholder="Your message..."
name="message"
/>
<button
className={cn(
'flex items-center justify-center',
'absolute right-1 top-1 px-4 font-bold h-8',
'bg-gray-100 dark:bg-gray-700 text-gray-900',
'dark:text-gray-100 rounded w-28'
)}
type="submit"
disabled={pending}
>
{pending ? <LoadingSpinner /> : 'Sign'}
</button>
</form>
{state?.successMessage ? (
<SuccessMessage>{state.successMessage}</SuccessMessage>
) : null}
{state?.errorMessage ? (
<ErrorMessage>{state.errorMessage}</ErrorMessage>
) : null}
</>
)
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
export default function ErrorMessage({ children }) {
export default function ErrorMessage({
children,
}: {
children: React.ReactNode
}) {
return (
<p className="flex items-center text-sm font-bold text-red-800 dark:text-red-400">
<svg
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
export default function SuccessMessage({ children }) {
export default function SuccessMessage({
children,
}: {
children: React.ReactNode
}) {
return (
<p className="flex items-center text-sm font-bold text-green-700 dark:text-green-400">
<svg
Expand Down
1 change: 1 addition & 0 deletions examples/with-fauna/jsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/actions/*": ["actions/*"],
"@/components/*": ["components/*"],
"@/lib/*": ["lib/*"]
}
Expand Down
7 changes: 0 additions & 7 deletions examples/with-fauna/lib/constants.js

This file was deleted.

49 changes: 0 additions & 49 deletions examples/with-fauna/lib/fauna.js

This file was deleted.

31 changes: 31 additions & 0 deletions examples/with-fauna/lib/fauna.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import 'server-only'
import { Client, fql, QuerySuccess, QueryValueObject } from 'fauna'

const client = new Client({
secret: process.env.FAUNA_CLIENT_SECRET,
})

export const getAllEntries = async () => {
try {
const dbresponse: QuerySuccess<QueryValueObject> = await client.query(fql`
Entry.all()
`)
return dbresponse.data.data
} catch (error: any) {
throw new Error(error.message)
}
}

export const createEntry = async (name: string, message: string) => {
try {
const dbresponse = await client.query(fql`
Entry.create({
name: ${name},
message: ${message},
createdAt: Time.now(),
})`)
return dbresponse.data
} catch (error: any) {
throw new Error(error.message)
}
}
7 changes: 7 additions & 0 deletions examples/with-fauna/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const nextConfig = {
experimental: {
serverActions: true,
},
}

module.exports = nextConfig
18 changes: 8 additions & 10 deletions examples/with-fauna/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,17 @@
"dependencies": {
"classnames": "2.3.1",
"date-fns": "2.28.0",
"faunadb": "4.5.4",
"graphql": "16.8.1",
"graphql-request": "4.3.0",
"fauna": "^1.2.0",
"next": "latest",
"react": "18.1.0",
"react-dom": "18.1.0",
"swr": "^2.0.0"
"react": "^18.2.0",
"react-dom": "^18.2.0",
"server-only": "^0.0.1"
},
"devDependencies": {
"autoprefixer": "^10.4.7",
"postcss": "^8.4.14",
"autoprefixer": "^10.4.16",
"postcss": "^8.4.31",
"request": "^2.88.2",
"stream-to-promise": "3.0.0",
"tailwindcss": "^3.1.2",
"request": "^2.88.2"
"tailwindcss": "^3.3.3"
}
}

0 comments on commit 0944fdd

Please sign in to comment.