Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
{
"typescript.tsdk": "node_modules\\typescript\\lib",
"typescript.enablePromptUseWorkspaceTsdk": true
"typescript.enablePromptUseWorkspaceTsdk": true,
"cSpell.words": [
"Autosize",
"hgetall",
"hset"
]
}
16 changes: 16 additions & 0 deletions components.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "default",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "tailwind.config.js",
"css": "app/globals.css",
"baseColor": "gray",
"cssVariables": false
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils"
}
}
6,730 changes: 6,730 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"@hookform/resolvers": "^3.1.0",
"@mantine/hooks": "^6.0.13",
"@next-auth/prisma-adapter": "^1.0.6",
"@prisma/client": "^4.14.1",
"@prisma/client": "^5.2.0",
"@radix-ui/react-avatar": "^1.0.3",
"@radix-ui/react-dropdown-menu": "^2.0.5",
"@radix-ui/react-label": "^2.0.2",
Expand Down
105 changes: 97 additions & 8 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,101 @@ model Session {
}

model User {
id String @id @default(cuid())
name String?
email String? @unique
emailVerified DateTime?

image String?
accounts Account[]
sessions Session[]
id String @id @default(cuid())
name String?
email String? @unique
emailVerified DateTime?
createdSubreddits Subreddit[] @relation("CreatedBy")

username String? @unique

image String?
accounts Account[]
sessions Session[]
Post Post[]
Comment Comment[]
CommentVote CommentVote[]
Vote Vote[]
Subscription Subscription[]
}

model Subreddit {
id String @id @default(cuid())
name String @unique
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
posts Post[]

creatorId String?
Creator User? @relation("CreatedBy", fields: [creatorId], references: [id])
subscribers Subscription[]

@@index([name])
}

model Subscription {
user User @relation(fields: [userId], references: [id])
userId String
subreddit Subreddit @relation(fields: [subredditId], references: [id])
subredditId String

@@id([userId, subredditId])
}

model Post {
id String @id @default(cuid())
title String
content Json?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
subreddit Subreddit @relation(fields: [subredditId], references: [id])
subredditId String

author User @relation(fields: [authorId], references: [id])
authorId String

comments Comment[]
votes Vote[]
}

model Comment {
id String @id @default(cuid())
text String
createdAt DateTime @default(now())
author User @relation(fields: [authorId], references: [id])
authorId String
post Post @relation(fields: [postId], references: [id])
postId String

replyToId String?
replyTo Comment? @relation("ReplyTo", fields: [replyToId], references: [id], onDelete: NoAction, onUpdate: NoAction)
replies Comment[] @relation("ReplyTo")

votes CommentVote[]
commentId String?
}

enum VoteType {
UP
DOWN
}

model Vote {
user User @relation(fields: [userId], references: [id])
userId String
post Post @relation(fields: [postId], references: [id])
postId String
type VoteType

@@id([userId, postId])
}

model CommentVote {
user User @relation(fields: [userId], references: [id])
userId String
comment Comment @relation(fields: [commentId], references: [id])
commentId String
type VoteType

@@id([userId, commentId])
}
26 changes: 26 additions & 0 deletions src/app/(auth)/sign-in/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { buttonVariants } from '@/components/ui/Button'
import { FC } from 'react'
import { cn } from '@/lib/utils'
import Link from 'next/link'
import SignIn from '@/components/SignIn'
import { ChevronLeft } from 'lucide-react'


const page: FC = () => {
return (<div className='absolute inset-0'>
<div className='h-full max-w-2xl mx-auto flex flex-col items-center justify-center gap-20'>
<Link
href='/'
className={cn(buttonVariants({ variant: 'ghost' }),
'self-start -mt-20')}>
<ChevronLeft className='mr-2 h-4 w-4' />
Home
</Link>

<SignIn />
</div>
</div>
)
}

export default page
26 changes: 26 additions & 0 deletions src/app/(auth)/sign-up/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { buttonVariants } from '@/components/ui/Button'
import { FC } from 'react'
import { cn } from '@/lib/utils'
import Link from 'next/link'
import SignUp from '@/components/SignUp'
import { ChevronLeft } from 'lucide-react'


const page = () => {
return (<div className='absolute inset-0'>
<div className='h-full max-w-2xl mx-auto flex flex-col items-center justify-center gap-20'>
<Link
href='/'
className={cn(buttonVariants({ variant: 'ghost' }),
'self-start -mt-20')}>
<ChevronLeft className='mr-2 h-4 w-4' />
Home
</Link>

<SignUp />
</div>
</div>
)
}

export default page
21 changes: 21 additions & 0 deletions src/app/@authModal/(.)sign-in/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import CloseModal from '@/components/CloseModal'
import SignIn from '@/components/SignIn'




const page = () => {
return <div className='fixed inset-0 bg-zinc-900/20 z-10'>
<div className='container flex items-center h-full max-w-lg mx-auto'>
<div className='relative bg-white w-full h-fit py-20 px-2 rounded-lg'>
<div className='absolute top-4 right-4'>
<CloseModal />
</div>

<SignIn />
</div>
</div>
</div>
}

export default page
19 changes: 19 additions & 0 deletions src/app/@authModal/(.)sign-up/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import CloseModal from '@/components/CloseModal'
import SignUp from '@/components/SignUp'


const page = ({ }) => {
return <div className='fixed inset-0 bg-zinc-900/20 z-10'>
<div className='container flex items-center h-full max-w-lg mx-auto'>
<div className='relative bg-white w-full h-fit py-20 px-2 rounded-lg'>
<div className='absolute top-4 right-4'>
<CloseModal />
</div>

<SignUp />
</div>
</div>
</div>
}

export default page
3 changes: 3 additions & 0 deletions src/app/@authModal/default.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function Default() {
return null;
}
6 changes: 6 additions & 0 deletions src/app/api/auth/[...nextauth]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { authOptions } from "@/lib/auth";
import NextAuth from "next-auth";

const handler = NextAuth(authOptions);

export { handler as GET, handler as POST }
35 changes: 35 additions & 0 deletions src/app/api/link/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import axios from "axios"

export async function GET(req: Request) {
const url = new URL(req.url)
const href = url.searchParams.get('url')

if (!href) {
return new Response('Invalid href', { status: 400 })
}

const res = await axios.get(href)

const titleMatch = res.data.match(/<title>(.*?)<\/title>/)
const title = titleMatch ? titleMatch[1] : ''

const descriptionMatch = res.data.match(/<meta name="description" content="(.*?)"/)
const description = descriptionMatch ? descriptionMatch[1] : ''

const imageMatch = res.data.match(/<meta property="og:image" content="(.*?)"/)
const imageUrl = imageMatch ? imageMatch[1] : ''

return new Response(
JSON.stringify({
success: 1,
meta: {
title,
description,
image: {
url: imageUrl,
}
}
})

)
}
82 changes: 82 additions & 0 deletions src/app/api/posts/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { getAuthSession } from "@/lib/auth"
import { db } from "@/lib/db"
import { z } from "zod"

export async function GET(req: Request) {
const url = new URL(req.url)

const session = await getAuthSession()

let followedCommunitiesIds: string[] = []

if (session) {
const followedCommunities = await db.subscription.findMany({
where: {
userId: session.user.id,
},
include: {
subreddit: true,
},
})

followedCommunitiesIds = followedCommunities.map(
({ subreddit }) => subreddit.id
)
}

try {
const { limit, page, subredditName } = z.object({
limit: z.string(),
page: z.string(),
subredditName: z.string().nullish().optional(),

}).parse({
subredditName: url.searchParams.get('subredditName'),
limit: url.searchParams.get('limit'),
page: url.searchParams.get('page'),
})

let whereClause = {}

if (subredditName) {
whereClause = {
subreddit: {
name: subredditName,
}
}
} else if (session) {
whereClause = {
subreddit: {
id: {
in: followedCommunitiesIds,
}
}
}
}

const posts = await db.post.findMany({
take: parseInt(limit),
skip: (parseInt(page) - 1) * parseInt(limit),
orderBy: {
createdAt: 'desc'
},
include: {
subreddit: true,
votes: true,
author: true,
comments: true,
},
where: whereClause,
})

return new Response(JSON.stringify(posts))

} catch (error) {
if (error instanceof z.ZodError) {
return new Response('Invalid request data passed', { status: 422 })
}

return new Response('Could not fetch more post, please try again later', { status: 500 })
}

}
Loading