diff --git a/declarations/iron-session.d.ts b/declarations/iron-session.d.ts index bddcf3354..08825de38 100644 --- a/declarations/iron-session.d.ts +++ b/declarations/iron-session.d.ts @@ -2,16 +2,9 @@ import "iron-session"; declare module "iron-session" { export interface IronSessionData { - user: - | { - id: string; - name: string; - email: string; - isGuest: false; - } - | { - id: string; - isGuest: true; - }; + user: { + id: string; + isGuest: boolean; + }; } } diff --git a/src/components/profile.tsx b/src/components/profile.tsx index 548a97093..92faa50f4 100644 --- a/src/components/profile.tsx +++ b/src/components/profile.tsx @@ -1,6 +1,6 @@ import { formatRelative } from "date-fns"; +import Head from "next/head"; import Link from "next/link"; -import { useRouter } from "next/router"; import { useTranslation } from "next-i18next"; import * as React from "react"; @@ -10,6 +10,7 @@ import User from "@/components/icons/user.svg"; import { trpc } from "../utils/trpc"; import { EmptyState } from "./empty-state"; +import LoginForm from "./login-form"; import { UserDetails } from "./profile/user-details"; import { useSession } from "./session"; @@ -19,21 +20,24 @@ export const Profile: React.VoidFunctionComponent = () => { const { t } = useTranslation("app"); const { data: userPolls } = trpc.useQuery(["user.getPolls"]); - const router = useRouter(); const createdPolls = userPolls?.polls; - React.useEffect(() => { - if (!user) { - router.replace("/new"); - } - }, [user, router]); - - if (!user || user.isGuest) { - return null; + if (user.isGuest) { + return ( +
+ + Profile - Login + + +
+ ); } return (
+ + Profile - {user.name} +
diff --git a/src/components/profile/user-details.tsx b/src/components/profile/user-details.tsx index f3687abe2..8eabbc85b 100644 --- a/src/components/profile/user-details.tsx +++ b/src/components/profile/user-details.tsx @@ -11,8 +11,8 @@ import { TextInput } from "../text-input"; export interface UserDetailsProps { userId: string; - name: string; - email: string; + name?: string; + email?: string; } const MotionButton = motion(Button); diff --git a/src/components/session.tsx b/src/components/session.tsx index cf7e1a7b2..7fc617197 100644 --- a/src/components/session.tsx +++ b/src/components/session.tsx @@ -4,6 +4,7 @@ import toast from "react-hot-toast"; import { trpc } from "@/utils/trpc"; +import FullPageLoader from "./full-page-loader"; import { useRequiredContext } from "./use-required-context"; export type UserSessionData = NonNullable; @@ -16,13 +17,23 @@ type ParticipantOrComment = { userId: string | null; }; -export type UserSessionDataExtended = UserSessionData & { - shortName: string; -}; +export type UserSessionDataExtended = + | { + isGuest: true; + id: string; + shortName: string; + } + | { + isGuest: false; + id: string; + name: string; + shortName: string; + email: string; + }; type SessionContextValue = { logout: () => void; - user: UserSessionDataExtended | null; + user: UserSessionDataExtended; refresh: () => void; ownsObject: (obj: ParticipantOrComment) => boolean; isLoading: boolean; @@ -35,14 +46,9 @@ SessionContext.displayName = "SessionContext"; export const SessionProvider: React.VoidFunctionComponent<{ children?: React.ReactNode; - defaultUser: UserSessionData; -}> = ({ children, defaultUser }) => { +}> = ({ children }) => { const queryClient = trpc.useContext(); - const { - data: user = defaultUser, - refetch, - isLoading, - } = trpc.useQuery(["session.get"]); + const { data: user, refetch, isLoading } = trpc.useQuery(["session.get"]); const logout = trpc.useMutation(["session.destroy"], { onSuccess: () => { @@ -50,6 +56,10 @@ export const SessionProvider: React.VoidFunctionComponent<{ }, }); + if (!user) { + return Loading user…; + } + const sessionData: SessionContextValue = { user: { ...user, @@ -95,7 +105,7 @@ export const withSession =

( const ComposedComponent: React.VoidFunctionComponent

= (props: P) => { const Component = component; return ( - + ); diff --git a/src/pages/login.tsx b/src/pages/login.tsx index 0d26e819a..c8532b301 100644 --- a/src/pages/login.tsx +++ b/src/pages/login.tsx @@ -100,8 +100,6 @@ export const getServerSideProps: GetServerSideProps = withSessionSsr( req.session.user = { isGuest: false, - name: user.name, - email: user.email, id: user.id, }; diff --git a/src/pages/profile.tsx b/src/pages/profile.tsx index c56a087cd..ea619bee5 100644 --- a/src/pages/profile.tsx +++ b/src/pages/profile.tsx @@ -1,40 +1,29 @@ import { NextPage } from "next"; -import Head from "next/head"; import { serverSideTranslations } from "next-i18next/serverSideTranslations"; import { withSessionSsr } from "@/utils/auth"; import { Profile } from "../components/profile"; -import { SessionProvider, UserSessionData } from "../components/session"; +import { withSession } from "../components/session"; import StandardLayout from "../components/standard-layout"; -const Page: NextPage<{ user: UserSessionData }> = ({ user }) => { - const name = user.isGuest ? user.id : user.name; +const Page: NextPage = () => { return ( - - - Profile - {name} - - - - - + + + ); }; export const getServerSideProps = withSessionSsr( - async ({ locale = "en", query, req }) => { - if (!req.session.user || req.session.user.isGuest) { - return { redirect: { destination: "/new" }, props: {} }; - } + async ({ locale = "en", query }) => { return { props: { ...(await serverSideTranslations(locale, ["app"])), ...query, - user: req.session.user, }, }; }, ); -export default Page; +export default withSession(Page); diff --git a/src/server/routers/polls.ts b/src/server/routers/polls.ts index efefa6f9c..d34e341be 100644 --- a/src/server/routers/polls.ts +++ b/src/server/routers/polls.ts @@ -96,6 +96,19 @@ export const polls = createRouter() resolve: async ({ ctx, input }): Promise<{ urlId: string }> => { const adminUrlId = await nanoid(); + let verified = false; + + if (ctx.session.user.isGuest === false) { + const user = await prisma.user.findUnique({ + where: { id: ctx.session.user.id }, + }); + + // If user is logged in with the same email address + if (user?.email === input.user.email) { + verified = true; + } + } + const poll = await prisma.poll.create({ data: { id: await nanoid(), @@ -106,9 +119,7 @@ export const polls = createRouter() description: input.description, authorName: input.user.name, demo: input.demo, - verified: - ctx.session.user?.isGuest === false && - ctx.session.user.email === input.user.email, + verified: verified, adminUrlId, participantUrlId: await nanoid(), user: { diff --git a/src/server/routers/polls/verification.ts b/src/server/routers/polls/verification.ts index 31de37200..e4bf3215e 100644 --- a/src/server/routers/polls/verification.ts +++ b/src/server/routers/polls/verification.ts @@ -49,8 +49,6 @@ export const verification = createRouter() ctx.session.user = { id: poll.user.id, isGuest: false, - name: poll.user.name, - email: poll.user.email, }; await ctx.session.save(); }, diff --git a/src/server/routers/session.ts b/src/server/routers/session.ts index 9077ea925..ce428118e 100644 --- a/src/server/routers/session.ts +++ b/src/server/routers/session.ts @@ -1,9 +1,36 @@ +import { prisma } from "~/prisma/db"; + +import { createGuestUser } from "../../utils/auth"; import { createRouter } from "../createRouter"; export const session = createRouter() .query("get", { - async resolve({ ctx }) { - return ctx.session.user; + async resolve({ + ctx, + }): Promise< + | { isGuest: true; id: string } + | { isGuest: false; id: string; name: string; email: string } + > { + if (ctx.session.user.isGuest) { + return { isGuest: true, id: ctx.session.user.id }; + } + + const user = await prisma.user.findUnique({ + where: { id: ctx.session.user.id }, + }); + + if (!user) { + ctx.session.user = await createGuestUser(); + await ctx.session.save(); + return { isGuest: true, id: ctx.session.user.id }; + } + + return { + isGuest: false, + id: user.id, + email: user.email, + name: user.name, + }; }, }) .mutation("destroy", { diff --git a/src/utils/auth.ts b/src/utils/auth.ts index 15dc794a7..0a89bfb45 100644 --- a/src/utils/auth.ts +++ b/src/utils/auth.ts @@ -51,7 +51,7 @@ export const createToken = async >( }); }; -const createGuestUser = async (): Promise<{ +export const createGuestUser = async (): Promise<{ isGuest: true; id: string; }> => {