Put meaningful data on each page
This commit is contained in:
@@ -47,17 +47,14 @@ model VerificationToken {
|
||||
|
||||
model User {
|
||||
id String @id @default(cuid())
|
||||
|
||||
email String @unique
|
||||
emailVerified DateTime?
|
||||
username String? @unique
|
||||
name String?
|
||||
bio String?
|
||||
email String @unique
|
||||
emailVerified DateTime?
|
||||
image String?
|
||||
|
||||
bio String?
|
||||
accounts Account[]
|
||||
sessions Session[]
|
||||
|
||||
authoredProjects Project[] @relation("author")
|
||||
projects Project[] @relation("members")
|
||||
}
|
||||
@@ -65,16 +62,13 @@ model User {
|
||||
model Project {
|
||||
id String @id @default(cuid())
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
title String
|
||||
description String
|
||||
bannerImageUrl String?
|
||||
|
||||
authorId String
|
||||
bannerImageUrl String?
|
||||
state ProjectLifecycle @default(PROPOSAL)
|
||||
author User @relation("author", fields: [authorId], references: [id])
|
||||
members User[] @relation("members")
|
||||
|
||||
state ProjectLifecycle @default(PROPOSAL)
|
||||
previews ProjectPreview[]
|
||||
|
||||
@@index([authorId])
|
||||
@@ -83,15 +77,23 @@ model Project {
|
||||
model ProjectPreview {
|
||||
projectState ProjectLifecycle
|
||||
projectId String
|
||||
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
||||
|
||||
title String?
|
||||
description String?
|
||||
cardImageUrl String?
|
||||
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([projectId, projectState])
|
||||
}
|
||||
|
||||
model members {
|
||||
A String
|
||||
B String
|
||||
|
||||
@@unique([A, B], map: "_members_AB_unique")
|
||||
@@index([B], map: "_members_B_index")
|
||||
@@map("_members")
|
||||
}
|
||||
|
||||
enum ProjectLifecycle {
|
||||
PROPOSAL
|
||||
IN_PROGRESS
|
||||
|
||||
15
src/components/projects/DisplayProjectCard.tsx
Normal file
15
src/components/projects/DisplayProjectCard.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import type { Project } from "@prisma/client";
|
||||
import { formatDate } from "@utils/filters";
|
||||
|
||||
export const DisplayProjectCard: React.FC<{ project: Project }> = ({
|
||||
project,
|
||||
}) => {
|
||||
return (
|
||||
<div key={project.id} className="mb-10">
|
||||
<h4 className="text-r-2xl font-medium">{project.title}</h4>
|
||||
<p className="text-r-sm">{formatDate(project.createdAt)}</p>
|
||||
<p className="text-r-sm">{project.state}</p>
|
||||
<p className="text-r-lg">{project.description}</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
18
src/components/projects/EditProjectCard.tsx
Normal file
18
src/components/projects/EditProjectCard.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import type { Project } from "@prisma/client";
|
||||
import { formatDate } from "@utils/filters";
|
||||
import Link from "next/link";
|
||||
|
||||
export const EditProjectCard: React.FC<{ project: Project }> = ({
|
||||
project,
|
||||
}) => {
|
||||
return (
|
||||
<Link href={`/projects/${project.id}`}>
|
||||
<div className="mb-10 rounded border-[6px] border-fg py-2 px-3">
|
||||
<h4 className="text-r-2xl font-medium">{project.title}</h4>
|
||||
<p className="text-r-sm">{formatDate(project.createdAt)}</p>
|
||||
<p className="text-r-sm">{project.state}</p>
|
||||
<p className="text-r-lg">{project.description}</p>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
@@ -1,17 +0,0 @@
|
||||
import Button from "@components/Button";
|
||||
import type { Project } from "@prisma/client";
|
||||
import dayjs from "dayjs";
|
||||
import relativeTime from "dayjs/plugin/relativeTime";
|
||||
|
||||
dayjs.extend(relativeTime);
|
||||
|
||||
export const ProjectCard: React.FC<{ project: Project }> = ({ project }) => {
|
||||
return (
|
||||
<div key={project.id} className="mb-10">
|
||||
<h4 className="text-r-2xl font-medium">{project.title}</h4>
|
||||
<p className="text-r-sm">{dayjs(project.createdAt).fromNow()}</p>
|
||||
<p className="text-r-sm">{project.state}</p>
|
||||
<p className="text-r-lg">{project.description}</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -80,7 +80,16 @@ export async function getServerSideProps(ctx: GetServerSidePropsContext) {
|
||||
const session = await getServerAuthSession(ctx);
|
||||
|
||||
if (!session) {
|
||||
const providers = await getProviders();
|
||||
// const providers = await getProviders();
|
||||
const providers = {
|
||||
google: {
|
||||
id: "google",
|
||||
name: "Google",
|
||||
type: "oauth",
|
||||
signinUrl: "http://localhost:3000/api/auth/signin/google",
|
||||
callbackUrl: "http://localhost:3000/api/auth/callback/google",
|
||||
},
|
||||
};
|
||||
return {
|
||||
props: {
|
||||
providers,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { DiscoverLayout } from "@components/layouts";
|
||||
import { api } from "@utils/api";
|
||||
import type { InferGetServerSidePropsType, NextPage } from "next";
|
||||
import { ProjectCard } from "@components/projects/ProjectCard";
|
||||
import { DisplayProjectCard } from "@components/projects/DisplayProjectCard";
|
||||
import { requireAuth } from "@components/HOC/requireAuth";
|
||||
|
||||
const Discover: NextPage<
|
||||
@@ -18,7 +18,7 @@ const Discover: NextPage<
|
||||
<p>Loading ...</p>
|
||||
) : (
|
||||
data?.map((project) => (
|
||||
<ProjectCard key={project.id} project={project} />
|
||||
<DisplayProjectCard key={project.id} project={project} />
|
||||
))
|
||||
)}
|
||||
</DiscoverLayout>
|
||||
|
||||
@@ -7,7 +7,7 @@ import type {
|
||||
InferGetServerSidePropsType,
|
||||
NextPage,
|
||||
} from "next";
|
||||
import { ProjectCard } from "@components/projects/ProjectCard";
|
||||
import { ProjectCard } from "@components/projects/DisplayProjectCard";
|
||||
import { requireAuth } from "@components/HOC/requireAuth";
|
||||
|
||||
const Discover: NextPage<
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { DiscoverLayout } from "@components/layouts";
|
||||
import { api } from "@utils/api";
|
||||
import type { InferGetServerSidePropsType, NextPage } from "next";
|
||||
import { ProjectCard } from "@components/projects/ProjectCard";
|
||||
import { DisplayProjectCard } from "@components/projects/DisplayProjectCard";
|
||||
import { requireAuth } from "@components/HOC/requireAuth";
|
||||
|
||||
const Discover: NextPage<
|
||||
@@ -18,7 +18,7 @@ const Discover: NextPage<
|
||||
<p>Loading ...</p>
|
||||
) : (
|
||||
data?.map((project) => (
|
||||
<ProjectCard key={project.id} project={project} />
|
||||
<DisplayProjectCard key={project.id} project={project} />
|
||||
))
|
||||
)}
|
||||
</DiscoverLayout>
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
import { DiscoverLayout } from "@components/layouts";
|
||||
import { getServerAuthSession } from "@server/auth";
|
||||
import { api } from "@utils/api";
|
||||
import type {
|
||||
GetServerSideProps,
|
||||
GetServerSidePropsContext,
|
||||
InferGetServerSidePropsType,
|
||||
NextPage,
|
||||
} from "next";
|
||||
import { ProjectCard } from "@components/projects/ProjectCard";
|
||||
import type { InferGetServerSidePropsType, NextPage } from "next";
|
||||
import { DisplayProjectCard } from "@components/projects/DisplayProjectCard";
|
||||
import { requireAuth } from "@components/HOC/requireAuth";
|
||||
|
||||
const Discover: NextPage<
|
||||
@@ -24,7 +18,7 @@ const Discover: NextPage<
|
||||
<p>Loading ...</p>
|
||||
) : (
|
||||
data?.map((project) => (
|
||||
<ProjectCard key={project.id} project={project} />
|
||||
<DisplayProjectCard key={project.id} project={project} />
|
||||
))
|
||||
)}
|
||||
</DiscoverLayout>
|
||||
|
||||
@@ -16,16 +16,24 @@ const Profile: NextPage<
|
||||
<h1 className="text-r-5xl font-bold text-primary">Profile</h1>
|
||||
{data && (
|
||||
<>
|
||||
<h2 className="text-r-4xl">{data.name}</h2>
|
||||
<p>{data.username}</p>
|
||||
<p>{data.name}</p>
|
||||
<p>{data.bio}</p>
|
||||
<p>
|
||||
|
||||
<h3 className="text-r-3xl">My Projects</h3>
|
||||
{data.authoredProjects.map((m) => (
|
||||
<>
|
||||
<p>{m.title}</p>
|
||||
<p>{m.description}</p>
|
||||
</>
|
||||
))}
|
||||
<h3 className="text-r-3xl">Projects I{"'"}ve Worked On</h3>
|
||||
{data.projects.map((m) => (
|
||||
<>
|
||||
<p>{m.title}</p>
|
||||
<p>{m.description}</p>
|
||||
</>
|
||||
))}
|
||||
</p>
|
||||
</>
|
||||
)}
|
||||
</MainLayout>
|
||||
|
||||
24
src/pages/projects/[projectId].tsx
Normal file
24
src/pages/projects/[projectId].tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import { requireAuth } from "@components/HOC/requireAuth";
|
||||
import { MainLayout } from "@components/layouts";
|
||||
import { api } from "@utils/api";
|
||||
import type { InferGetServerSidePropsType, NextPage } from "next";
|
||||
|
||||
const SpecificProject: NextPage<
|
||||
InferGetServerSidePropsType<typeof getServerSideProps>
|
||||
> = ({ projectId }) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
const { data } = api.projects.getProjectById.useQuery({ projectId });
|
||||
|
||||
return (
|
||||
<MainLayout>
|
||||
<p>{data?.id}</p>
|
||||
</MainLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default SpecificProject;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
export const getServerSideProps = requireAuth(async (ctx) => {
|
||||
return { props: { projectId: ctx.params?.projectId } };
|
||||
});
|
||||
@@ -1,11 +1,28 @@
|
||||
import type { NextPage } from "next";
|
||||
import { MainLayout } from "@components/layouts";
|
||||
import { requireAuth } from "@components/HOC/requireAuth";
|
||||
import { api } from "@utils/api";
|
||||
import { useMemo } from "react";
|
||||
import { EditProjectCard } from "@components/projects/EditProjectCard";
|
||||
|
||||
const Projects: NextPage = () => {
|
||||
const { data } = api.projects.getAllByCurrentUser.useQuery();
|
||||
|
||||
const sortedProjects = useMemo(() => {
|
||||
if (!data) return [];
|
||||
|
||||
const projects = data.projects.concat(data.authoredProjects);
|
||||
return projects.sort(
|
||||
(a, b) => b.createdAt.getTime() - a.createdAt.getTime()
|
||||
);
|
||||
}, [data]);
|
||||
|
||||
return (
|
||||
<MainLayout>
|
||||
<h1 className="text-r-5xl font-bold text-primary">Projects</h1>
|
||||
{sortedProjects.map((p) => (
|
||||
<EditProjectCard key={p.id} project={p} />
|
||||
))}
|
||||
</MainLayout>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -13,6 +13,7 @@ export const profileRouter = createTRPCRouter({
|
||||
name: true,
|
||||
bio: true,
|
||||
image: true,
|
||||
authoredProjects: true,
|
||||
projects: true,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { proposalSchema } from "@utils/constants/schema/project";
|
||||
import { Project, ProjectLifecycle } from "@prisma/client";
|
||||
import { ProjectLifecycle } from "@prisma/client";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createTRPCRouter, publicProcedure, protectedProcedure } from "../trpc";
|
||||
@@ -11,6 +11,12 @@ export const projectsRouter = createTRPCRouter({
|
||||
orderBy: [{ createdAt: "desc" }],
|
||||
});
|
||||
}),
|
||||
getAllByCurrentUser: protectedProcedure.query(({ ctx }) => {
|
||||
return ctx.prisma.user.findUnique({
|
||||
where: { id: ctx.session.user.id },
|
||||
select: { authoredProjects: true, projects: true },
|
||||
});
|
||||
}),
|
||||
getAllByUserId: publicProcedure
|
||||
.input(
|
||||
z.object({
|
||||
@@ -36,6 +42,17 @@ export const projectsRouter = createTRPCRouter({
|
||||
orderBy: [{ createdAt: "desc" }],
|
||||
});
|
||||
}),
|
||||
getProjectById: publicProcedure
|
||||
.input(
|
||||
z.object({
|
||||
projectId: z.string(),
|
||||
})
|
||||
)
|
||||
.query(({ ctx, input }) => {
|
||||
return ctx.prisma.project.findUnique({
|
||||
where: { id: input.projectId },
|
||||
});
|
||||
}),
|
||||
createProposal: protectedProcedure
|
||||
.input(proposalSchema)
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
import dayjs from "dayjs";
|
||||
import relativeTime from "dayjs/plugin/relativeTime";
|
||||
|
||||
dayjs.extend(relativeTime);
|
||||
|
||||
export const formatDate = (date: Date) => dayjs(date).fromNow();
|
||||
|
||||
export const getQueryOrDefault = (
|
||||
value: string | string[] | undefined,
|
||||
fallback: string
|
||||
|
||||
Reference in New Issue
Block a user