Can navigate to landing page from authed pages
This commit is contained in:
@@ -2,7 +2,8 @@ import type { Children } from "@utils/types/props";
|
|||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { cva, cx } from "class-variance-authority";
|
import { cva, cx } from "class-variance-authority";
|
||||||
import { Button } from "@components/Button";
|
import { Button } from "@components/Button";
|
||||||
import { signIn } from "next-auth/react";
|
import { signIn, useSession } from "next-auth/react";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
export const HomeLayout: React.FC<Children> = ({ children }) => {
|
export const HomeLayout: React.FC<Children> = ({ children }) => {
|
||||||
return (
|
return (
|
||||||
@@ -33,7 +34,7 @@ const Header: React.FC = () => {
|
|||||||
|
|
||||||
// Scroll Listener
|
// Scroll Listener
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const listenScrollEvent = () => {
|
const listenScrollEvent: () => void = () => {
|
||||||
const threshold = 25;
|
const threshold = 25;
|
||||||
setIsLargeBar(
|
setIsLargeBar(
|
||||||
document.body.scrollTop < threshold &&
|
document.body.scrollTop < threshold &&
|
||||||
@@ -47,18 +48,6 @@ const Header: React.FC = () => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const FlexDivider = () => <span className="text-r-2xl text-fg/25">||</span>;
|
|
||||||
|
|
||||||
const Background = () => (
|
|
||||||
<div
|
|
||||||
className={cx(
|
|
||||||
"absolute inset-0 -z-10",
|
|
||||||
"bg-gradient-to-b from-bg via-bg/60 to-transparent",
|
|
||||||
"backdrop-blur [mask:linear-gradient(black_75%,transparent)]"
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header
|
<header
|
||||||
className={header({
|
className={header({
|
||||||
@@ -79,22 +68,60 @@ const Header: React.FC = () => {
|
|||||||
Premium
|
Premium
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<CTAButton />
|
||||||
variant={{ size: "small" }}
|
|
||||||
onClick={() =>
|
|
||||||
void signIn(undefined, {
|
|
||||||
callbackUrl: "/projects",
|
|
||||||
redirect: false,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
>
|
|
||||||
Sign In
|
|
||||||
</Button>
|
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const FlexDivider: React.FC = () => (
|
||||||
|
<span className="text-r-2xl text-fg/25">||</span>
|
||||||
|
);
|
||||||
|
|
||||||
|
const Background: React.FC = () => (
|
||||||
|
<div
|
||||||
|
className={cx(
|
||||||
|
"absolute inset-0 -z-10",
|
||||||
|
"bg-gradient-to-b from-bg via-bg/60 to-transparent",
|
||||||
|
"backdrop-blur [mask:linear-gradient(black_75%,transparent)]"
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
const CTAButton: React.FC = () => {
|
||||||
|
const session = useSession();
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
if (session.status === "authenticated") {
|
||||||
|
const username = session.data.user.username ?? "";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
variant={{ size: "small" }}
|
||||||
|
onClick={() => {
|
||||||
|
void signIn(undefined, {
|
||||||
|
callbackUrl: `/profile/${username}`,
|
||||||
|
redirect: false,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{username}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
variant={{ size: "small" }}
|
||||||
|
onClick={() => {
|
||||||
|
void router.push(`/projects`);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Sign In
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
// === Footer =================================================================
|
// === Footer =================================================================
|
||||||
|
|
||||||
const Footer: React.FC = () => {
|
const Footer: React.FC = () => {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
FiUser,
|
FiUser,
|
||||||
FiLogOut,
|
FiLogOut,
|
||||||
FiSettings,
|
FiSettings,
|
||||||
|
FiExternalLink,
|
||||||
} from "react-icons/fi";
|
} from "react-icons/fi";
|
||||||
import type { IconType } from "react-icons/lib";
|
import type { IconType } from "react-icons/lib";
|
||||||
import { Button } from "@components/Button";
|
import { Button } from "@components/Button";
|
||||||
@@ -220,6 +221,7 @@ const MoreMenu: React.FC = () => {
|
|||||||
className="min-w-[250px] rounded-md bg-bg-700 p-3 data-[side=top]:animate-slideUpAndFade"
|
className="min-w-[250px] rounded-md bg-bg-700 p-3 data-[side=top]:animate-slideUpAndFade"
|
||||||
sideOffset={10}
|
sideOffset={10}
|
||||||
>
|
>
|
||||||
|
{/* Settings */}
|
||||||
<DropdownMenu.Item>
|
<DropdownMenu.Item>
|
||||||
<Link
|
<Link
|
||||||
href="/settings"
|
href="/settings"
|
||||||
@@ -229,6 +231,19 @@ const MoreMenu: React.FC = () => {
|
|||||||
<FiSettings />
|
<FiSettings />
|
||||||
</Link>
|
</Link>
|
||||||
</DropdownMenu.Item>
|
</DropdownMenu.Item>
|
||||||
|
|
||||||
|
{/* Landing page */}
|
||||||
|
<DropdownMenu.Item>
|
||||||
|
<Link
|
||||||
|
href="/"
|
||||||
|
className="flex w-full select-none items-center justify-between px-[5px] pl-[25px] outline-none"
|
||||||
|
>
|
||||||
|
<p className="text-r-lg">Parallel Homepage</p>
|
||||||
|
<FiExternalLink />
|
||||||
|
</Link>
|
||||||
|
</DropdownMenu.Item>
|
||||||
|
|
||||||
|
{/* Sign out */}
|
||||||
<DropdownMenu.Item>
|
<DropdownMenu.Item>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@@ -31,13 +31,7 @@ export const getServerSideProps: GetServerSideProps = async (
|
|||||||
) => {
|
) => {
|
||||||
const session = await getServerAuthSession(ctx);
|
const session = await getServerAuthSession(ctx);
|
||||||
|
|
||||||
if (session && session.user) {
|
return { props: { session: session } };
|
||||||
return {
|
|
||||||
redirect: { destination: "/projects", permanent: false },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return { props: { session } };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Home;
|
export default Home;
|
||||||
|
|||||||
@@ -1,17 +1,79 @@
|
|||||||
|
import Button from "@components/Button";
|
||||||
import { requireAuth } from "@components/HOC/requireAuth";
|
import { requireAuth } from "@components/HOC/requireAuth";
|
||||||
import { MainLayout } from "@components/layouts";
|
import { MainLayout } from "@components/layouts";
|
||||||
|
import { ProjectLifecycle } from "@prisma/client";
|
||||||
import { api } from "@utils/api";
|
import { api } from "@utils/api";
|
||||||
|
import { formatDate } from "@utils/filters";
|
||||||
import type { InferGetServerSidePropsType, NextPage } from "next";
|
import type { InferGetServerSidePropsType, NextPage } from "next";
|
||||||
|
|
||||||
|
const StateOrder: ProjectLifecycle[] = Object.values(ProjectLifecycle);
|
||||||
|
|
||||||
const SpecificProject: NextPage<
|
const SpecificProject: NextPage<
|
||||||
InferGetServerSidePropsType<typeof getServerSideProps>
|
InferGetServerSidePropsType<typeof getServerSideProps>
|
||||||
> = ({ projectId }) => {
|
> = ({ projectId }) => {
|
||||||
|
const ctx = api.useContext();
|
||||||
|
|
||||||
|
const { data, isRefetching } = api.projects.getProjectById.useQuery({
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||||
|
projectId,
|
||||||
|
});
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||||
const { data } = api.projects.getProjectById.useQuery({ projectId });
|
const { mutate, isLoading: isUpdatingState } =
|
||||||
|
api.projects.updateState.useMutation({
|
||||||
|
onSuccess: () => {
|
||||||
|
void ctx.projects.getProjectById.invalidate();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const changeState = (diff: -1 | 1) => {
|
||||||
|
if (!data) return;
|
||||||
|
|
||||||
|
const newState =
|
||||||
|
StateOrder[
|
||||||
|
StateOrder.findIndex((state) => state === data.state) + diff
|
||||||
|
] ?? data.state;
|
||||||
|
|
||||||
|
if (newState !== data.state) {
|
||||||
|
mutate({
|
||||||
|
projectId: data.id,
|
||||||
|
state: newState,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MainLayout>
|
<MainLayout>
|
||||||
<p>{data?.id}</p>
|
{!data ? (
|
||||||
|
<p>Loading...</p>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<p>{data.title}</p>
|
||||||
|
<p>{formatDate(data.createdAt)}</p>
|
||||||
|
<p>{data.description}</p>
|
||||||
|
<p>ID: {data.id}</p>
|
||||||
|
<p>State: {data.state}</p>
|
||||||
|
<div className="flex flex-row gap-x-4">
|
||||||
|
<Button
|
||||||
|
variant={{ size: "small" }}
|
||||||
|
disabled={
|
||||||
|
data.state === "PROPOSAL" || isUpdatingState || isRefetching
|
||||||
|
}
|
||||||
|
onClick={() => changeState(-1)}
|
||||||
|
>
|
||||||
|
Prev State
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant={{ size: "small" }}
|
||||||
|
disabled={
|
||||||
|
data.state === "COMPLETE" || isUpdatingState || isRefetching
|
||||||
|
}
|
||||||
|
onClick={() => changeState(1)}
|
||||||
|
>
|
||||||
|
Next State
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</MainLayout>
|
</MainLayout>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ export const projectsRouter = createTRPCRouter({
|
|||||||
const projects = await ctx.prisma.project.findMany({
|
const projects = await ctx.prisma.project.findMany({
|
||||||
where: { state: input.state },
|
where: { state: input.state },
|
||||||
select: {
|
select: {
|
||||||
|
id: true,
|
||||||
author: true,
|
author: true,
|
||||||
members: true,
|
members: true,
|
||||||
bannerImageUrl: true,
|
bannerImageUrl: true,
|
||||||
@@ -51,11 +52,15 @@ export const projectsRouter = createTRPCRouter({
|
|||||||
take: 100,
|
take: 100,
|
||||||
orderBy: [{ createdAt: "desc" }],
|
orderBy: [{ createdAt: "desc" }],
|
||||||
});
|
});
|
||||||
projects.map((p) => ({
|
|
||||||
|
return projects.map((p) => ({
|
||||||
members: (() => {
|
members: (() => {
|
||||||
p.members.push(p.author);
|
p.members.push(p.author);
|
||||||
return p.members.map((m) => m.username);
|
return p.members
|
||||||
|
.map((m) => m.username)
|
||||||
|
.filter((username) => !!username) as string[];
|
||||||
})(),
|
})(),
|
||||||
|
id: p.id,
|
||||||
createdAt: p.createdAt,
|
createdAt: p.createdAt,
|
||||||
title: p.title,
|
title: p.title,
|
||||||
description: p.description,
|
description: p.description,
|
||||||
@@ -85,4 +90,18 @@ export const projectsRouter = createTRPCRouter({
|
|||||||
|
|
||||||
return proposal;
|
return proposal;
|
||||||
}),
|
}),
|
||||||
|
updateState: protectedProcedure
|
||||||
|
.input(
|
||||||
|
z.object({
|
||||||
|
state: z.nativeEnum(ProjectLifecycle),
|
||||||
|
projectId: z.string(),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.mutation(async ({ ctx, input }) => {
|
||||||
|
const { projectId, state } = input;
|
||||||
|
await ctx.prisma.project.update({
|
||||||
|
where: { id: projectId },
|
||||||
|
data: { state },
|
||||||
|
});
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user