├── app ├── favicon.ico ├── api │ ├── post │ │ └── [id] │ │ │ └── route.js │ └── add-post │ │ └── route.js ├── components │ ├── Post.jsx │ └── DeletePostButton.jsx ├── layout.js ├── page.jsx ├── add-post │ └── page.jsx ├── globals.css └── page.module.css ├── jsconfig.json ├── next.config.js ├── lib └── prisma.js ├── package.json ├── .gitignore ├── public ├── vercel.svg └── next.svg ├── schema.prisma └── README.md /app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coderyansolomon/fullstack-intro/HEAD/app/favicon.ico -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "paths": { 4 | "@/*": ["./*"] 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {} 3 | 4 | module.exports = nextConfig 5 | -------------------------------------------------------------------------------- /app/api/post/[id]/route.js: -------------------------------------------------------------------------------- 1 | import { NextResponse } from "next/server"; 2 | import prisma from "@/lib/prisma"; 3 | 4 | export async function DELETE(request, {params}){ 5 | const id = params.id; 6 | 7 | const post = await prisma.post.delete({ 8 | where: {id} 9 | }) 10 | 11 | return NextResponse.json(post) 12 | } -------------------------------------------------------------------------------- /lib/prisma.js: -------------------------------------------------------------------------------- 1 | import { PrismaClient } from "@prisma/client"; 2 | 3 | let prisma; 4 | 5 | if (process.env.NODE_ENV === 'production'){ 6 | prisma = new PrismaClient() 7 | } else { 8 | if (!global.prisma){ 9 | global.prisma = new PrismaClient() 10 | } 11 | prisma = global.prisma 12 | } 13 | 14 | export default prisma; -------------------------------------------------------------------------------- /app/components/Post.jsx: -------------------------------------------------------------------------------- 1 | import DeletePostButton from "./DeletePostButton"; 2 | 3 | export default function Post({id, title, content, authorName}){ 4 | return ( 5 |
6 |

{authorName}

7 |

{title}

8 |

{content}

9 | 10 |
11 | ) 12 | } -------------------------------------------------------------------------------- /app/layout.js: -------------------------------------------------------------------------------- 1 | import './globals.css' 2 | import { Inter } from 'next/font/google' 3 | 4 | const inter = Inter({ subsets: ['latin'] }) 5 | 6 | export const metadata = { 7 | title: 'Create Next App', 8 | description: 'Generated by create next app', 9 | } 10 | 11 | export default function RootLayout({ children }) { 12 | return ( 13 | 14 | {children} 15 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "full-stack-intro", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint", 10 | "postinstall": "prisma generate" 11 | }, 12 | "dependencies": { 13 | "@prisma/client": "^5.1.1", 14 | "next": "13.4.16", 15 | "react": "18.2.0", 16 | "react-dom": "18.2.0" 17 | }, 18 | "devDependencies": { 19 | "prisma": "^5.1.1" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env*.local 29 | .env 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /app/api/add-post/route.js: -------------------------------------------------------------------------------- 1 | import prisma from "@/lib/prisma"; 2 | import { NextResponse } from "next/server" 3 | 4 | export async function POST(request){ 5 | const res = await request.json() 6 | const {title, content} = res; 7 | const result = await prisma.post.create({ 8 | data: { 9 | title, 10 | content, 11 | published: true, 12 | author: {create: { 13 | name: 'ryan' 14 | }} 15 | } 16 | }) 17 | 18 | return NextResponse.json({result}) 19 | } -------------------------------------------------------------------------------- /app/components/DeletePostButton.jsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | import { useRouter } from "next/navigation" 3 | 4 | export default function DeletePostButton({postId}){ 5 | const router = useRouter() 6 | 7 | async function handleClick(){ 8 | 9 | try { 10 | await fetch(`/api/post/${postId}`, { 11 | method: 'DELETE' 12 | }) 13 | router.refresh() 14 | } catch(e){ 15 | console.error(e) 16 | } 17 | 18 | } 19 | 20 | return ( 21 | 22 | ) 23 | } -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /schema.prisma: -------------------------------------------------------------------------------- 1 | // schema.prisma 2 | 3 | generator client { 4 | provider = "prisma-client-js" 5 | previewFeatures = ["jsonProtocol"] 6 | } 7 | 8 | datasource db { 9 | provider = "postgresql" 10 | url = env("POSTGRES_PRISMA_URL") // uses connection pooling 11 | directUrl = env("POSTGRES_URL_NON_POOLING") // uses a direct connection 12 | } 13 | 14 | model Post { 15 | id String @default(cuid()) @id 16 | title String 17 | content String? 18 | published Boolean @default(false) 19 | author User? @relation(fields: [authorId], references: [id]) 20 | authorId String? 21 | } 22 | 23 | model User { 24 | id String @default(cuid()) @id 25 | name String? 26 | email String? @unique 27 | createdAt DateTime @default(now()) @map(name: "created_at") 28 | updatedAt DateTime @updatedAt @map(name: "updated_at") 29 | posts Post[] 30 | @@map(name: "users") 31 | } -------------------------------------------------------------------------------- /app/page.jsx: -------------------------------------------------------------------------------- 1 | import Link from 'next/link'; 2 | import Post from './components/Post'; 3 | import styles from './page.module.css' 4 | import prisma from '@/lib/prisma' 5 | 6 | async function getPosts(){ 7 | const posts = await prisma.post.findMany({ 8 | where: {published: true}, 9 | include: { 10 | author: { 11 | select: {name: true} 12 | } 13 | } 14 | }) 15 | return posts; 16 | } 17 | 18 | export default async function Home() { 19 | const posts = await getPosts(); 20 | return ( 21 |
22 | Add Post 23 |

Feed

24 | { 25 | posts.map((post) => { 26 | return ( 27 | 34 | ) 35 | }) 36 | } 37 |
38 | ) 39 | } 40 | -------------------------------------------------------------------------------- /public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | # or 12 | pnpm dev 13 | ``` 14 | 15 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 16 | 17 | You can start editing the page by modifying `app/page.js`. The page auto-updates as you edit the file. 18 | 19 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. 20 | 21 | ## Learn More 22 | 23 | To learn more about Next.js, take a look at the following resources: 24 | 25 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 26 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 27 | 28 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 29 | 30 | ## Deploy on Vercel 31 | 32 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 33 | 34 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 35 | -------------------------------------------------------------------------------- /app/add-post/page.jsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | import styles from '@/app/page.module.css' 3 | import Link from 'next/link'; 4 | import { useState } from 'react'; 5 | import { useRouter } from 'next/navigation'; 6 | 7 | export default function AddPost(){ 8 | const [title, setTitle] = useState(''); 9 | const [content, setContent] = useState(''); 10 | const router = useRouter() 11 | 12 | const handleTitleChange = (event) => { 13 | setTitle(event.target.value); 14 | }; 15 | 16 | const handleContentChange = (event) => { 17 | setContent(event.target.value); 18 | }; 19 | 20 | const handleSubmit = async (event) => { 21 | event.preventDefault(); 22 | 23 | try{ 24 | await fetch('/api/add-post', { 25 | method: 'POST', 26 | headers: { 27 | 'Content-Type': 'application/json' 28 | }, 29 | body: JSON.stringify({title, content}) }) 30 | 31 | router.refresh() 32 | } catch (error){ 33 | console.error(error) 34 | } 35 | 36 | setTitle(''); 37 | setContent(''); 38 | }; 39 | 40 | return ( 41 |
42 | View Feed 43 |

Add Post

44 |
45 |
46 | 47 | 54 |
55 |
56 | 57 |