Skip to content

Commit

Permalink
added all the interim functionality and features, will add more..
Browse files Browse the repository at this point in the history
  • Loading branch information
jasondev01 committed Sep 10, 2023
1 parent 9f26216 commit 349af85
Show file tree
Hide file tree
Showing 32 changed files with 1,310 additions and 45 deletions.
10 changes: 10 additions & 0 deletions app/api/auth/token/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { getToken } from "next-auth/jwt";
import { NextRequest, NextResponse } from "next/server";

const secret = process.env.NEXTAUTH_SECRET;

export async function GET(req: NextRequest) {
const token = await getToken({ req, secret, raw: true });

return NextResponse.json({ token }, { status: 200 })
}
34 changes: 34 additions & 0 deletions app/api/upload/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { NextResponse } from "next/server";
import { v2 as cloudinary } from 'cloudinary';

cloudinary.config({
cloud_name: process.env.CLOUDINARY_NAME,
api_key: process.env.CLOUDINARY_KEY,
api_secret: process.env.CLOUDINARY_SECRET,
});

export async function POST(req: Request) {
const { path } = await req.json();

if(!path) {
return NextResponse.json(
{ message: 'Image path is required' },
{ status: 400 }
)
}

try {
const options = {
use_filename: true,
unique_filename: false,
overwrite: true,
transformation: [{ width: 1000, height: 752, crop: 'scale' }]
}

const result = await cloudinary.uploader.upload(path, options)

return NextResponse.json(result, { status: 200 })
} catch (error) {
return NextResponse.json({ message: error }, { status: 500 })
}
}
23 changes: 23 additions & 0 deletions app/create-project/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import Modal from "@/components/Modal"
import ProjectForm from "@/components/ProjectForm"
import { getCurrentUser } from "@/lib/session"
import { redirect } from "next/navigation";


const CreateProject = async () => {
const session = await getCurrentUser();
if (!session) redirect('/')
return (
<Modal>
<h3 className="modal-head-text">
Create a New Project
</h3>
<ProjectForm
type='create'
session={session}
/>
</Modal>
)
}

export default CreateProject
29 changes: 29 additions & 0 deletions app/edit-project/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { ProjectInterface } from "@/common.types";
import Modal from "@/components/Modal"
import ProjectForm from "@/components/ProjectForm"
import { getProjectDetails } from "@/lib/actions";
import { getCurrentUser } from "@/lib/session"
import { redirect } from "next/navigation";


const EditProject = async ({ params: { id } }: { params: { id: string } }) => {
const session = await getCurrentUser();
if (!session) redirect('/')

const result = await getProjectDetails(id) as { project?: ProjectInterface }

return (
<Modal>
<h3 className="modal-head-text">
Edit Project
</h3>
<ProjectForm
type='edit'
session={session}
project={result?.project}
/>
</Modal>
)
}

export default EditProject
6 changes: 1 addition & 5 deletions app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,7 @@ export const metadata = {
description: "Showcase and discover remarkable developer projects",
};

export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
export default function RootLayout({ children, }: { children: React.ReactNode; }) {
return (
<html lang="en">
<body>
Expand Down
73 changes: 69 additions & 4 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,76 @@
import { ProjectInterface } from "@/common.types"
import Categories from "@/components/Categories";
import LoadMore from "@/components/LoadMore";
import ProjectCard from "@/components/ProjectCard";
import { fetchAllProjects } from "@/lib/actions"

type ProjectSearch = {
projectSearch: {
edges: { node: ProjectInterface}[];
pageInfo: {
hasPreviousPage: boolean
hasNextPage: boolean
startCursor: string
endCursor: string
}
}
}

type SearchParamms = {
category?: string
endcursor?: string
}

type Props = {
searchParams: SearchParamms
}

export const dynamic = 'force-dynamic';
export const dynamicParams = true;
export const revalidate = 0;

const Home = async ({ searchParams: { category, endcursor } }: Props) => {
const data = await fetchAllProjects(category, endcursor) as ProjectSearch

const projectsToDisplay = data?.projectSearch?.edges || []

if (projectsToDisplay.length === 0) {
return (
<section className="flexStart flex-col paddings">
<Categories />
<p className="no-result-text text-center">
No found, go create some first
</p>
</section>
)
}

const pagination = data?.projectSearch?.pageInfo

const Home = () => {
return (
<section className="flex-start flex-col paddings mb-16">
<h1>Categories</h1>
<h1>Posts</h1>
<h1>LoadMore</h1>
<Categories />
<section className="projects-grid">
{
projectsToDisplay?.map(({ node }: { node: ProjectInterface }) => (
<ProjectCard
key={`${node?.id}`}
id={node?.id}
image={node?.image}
title={node?.title}
name={node?.createdBy.name}
avatarUrl={node?.createdBy?.avatarUrl}
userId={node?.createdBy?.id}
/>
))
}
</section>
<LoadMore
startCursor={pagination?.startCursor}
endCursor={pagination?.endCursor}
hasPreviousPage={pagination?.hasPreviousPage}
hasNextPage={pagination?.hasNextPage}
/>
</section>
)
}
Expand Down
25 changes: 25 additions & 0 deletions app/profile/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { UserProfile } from "@/common.types"
import ProfilePage from "@/components/ProfilePage"
import { getUserProjects } from "@/lib/actions"

type Props = {
params: {
id: string
}
}

const UserProfile = async ({ params }: Props) => {
const result = await getUserProjects(params.id, 100) as { user: UserProfile }

if (!result?.user) return <p className="no-result-text">Failed to Fetch User Info</p>


return (
<ProfilePage
user={result?.user}
/>

)
}

export default UserProfile
113 changes: 113 additions & 0 deletions app/project/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import Image from "next/image"
import Link from "next/link"

import { getCurrentUser } from "@/lib/session"
import { getProjectDetails } from "@/lib/actions"
import Modal from "@/components/Modal"
// import ProjectActions from "@/components/ProjectActions"
import RelatedProjects from "@/components/RelatedProjects"
import { ProjectInterface } from "@/common.types"
import ProjectActions from "@/components/ProjectActions"

const Project = async ({ params: { id } }: { params: { id: string } }) => {
const session = await getCurrentUser()
const result = await getProjectDetails(id) as { project?: ProjectInterface}

if (!result?.project) return (
<p className="no-result-text">Failed to fetch project info</p>
)

const projectDetails = result?.project

const renderLink = () => `/profile/${projectDetails?.createdBy?.id}`

return (
<Modal>
<section className="flexBetween gap-y-8 max-w-4xl max-xs:flex-col w-full">
<div className="flex-1 flex items-start gap-5 w-full max-xs:flex-col">
<Link href={renderLink()}>
<Image
src={projectDetails?.createdBy?.avatarUrl}
width={50}
height={50}
alt="profile"
className="rounded-full"
/>
</Link>

<div className="flex-1 flexStart flex-col gap-1">
<p className="self-start text-lg font-semibold">
{projectDetails?.title}
</p>
<div className="user-info">
<Link href={renderLink()}>
{projectDetails?.createdBy?.name}
</Link>
<Image src="/dot.svg" width={4} height={4} alt="dot" />
<Link href={`/?category=${projectDetails.category}`} className="text-primary-purple font-semibold">
{projectDetails?.category}
</Link>
</div>
</div>
</div>

{
session?.user?.email === projectDetails?.createdBy?.email && (
<div className="flex justify-end items-center gap-2">
<ProjectActions
projectId={projectDetails?.id}
/>
</div>
)
}
</section>

<section className="mt-14">
<Image
src={`${projectDetails?.image}`}
className="object-cover rounded-2xl"
width={1064}
height={798}
alt="poster"
/>
</section>

<section className="flexCenter flex-col mt-20">
<p className="max-w-5xl text-xl font-normal">
{projectDetails?.description}
</p>

<div className="flex flex-wrap mt-5 gap-5">
<Link href={projectDetails?.githubUrl} target="_blank" rel="noreferrer" className="flexCenter gap-2 tex-sm font-medium text-primary-purple">
🖥 <span className="underline">Github</span>
</Link>
<Image src="/dot.svg" width={4} height={4} alt="dot" />
<Link href={projectDetails?.liveSiteUrl} target="_blank" rel="noreferrer" className="flexCenter gap-2 tex-sm font-medium text-primary-purple">
🚀 <span className="underline">Live Site</span>
</Link>
</div>
</section>

<section className="flexCenter w-full gap-8 mt-28">
<span className="w-full h-0.5 bg-light-white-200" />
<Link href={renderLink()} className="min-w-[82px] h-[82px]">
<Image
src={projectDetails?.createdBy?.avatarUrl}
className="rounded-full"
width={82}
height={82}
alt="profile image"
/>
</Link>
<span className="w-full h-0.5 bg-light-white-200" />
</section>

<RelatedProjects
userId={projectDetails?.createdBy?.id}
projectId={projectDetails?.id}
/>
</Modal>
)
}

export default Project
18 changes: 10 additions & 8 deletions components/AuthProviders.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import { getProviders, signIn } from 'next-auth/react'
import { useState, useEffect } from 'react'
import Button from './Button'

type Provider = {
id: string
Expand Down Expand Up @@ -29,14 +30,15 @@ const AuthProviders = () => {
if(providers) {
return (
<div>
{Object.values(providers).map((provider: Provider, i) => (
<button
key={i}
onClick={() => signIn(provider?.id)}
>
{provider.id}
</button>
))}
{
Object.values(providers).map((provider: Provider, i) => (
<Button
key={i}
title='Sign In'
handleClick={() => signIn(provider?.id)}
/>
))
}
</div>
)
}
Expand Down
Loading

0 comments on commit 349af85

Please sign in to comment.