mirror of
https://github.com/lukevella/rallly.git
synced 2025-05-14 17:36:49 +02:00
Prefetch user (#429)
This commit is contained in:
parent
37f777cace
commit
249376c43e
20 changed files with 220 additions and 181 deletions
|
@ -18,9 +18,9 @@ import {
|
|||
UserDetailsData,
|
||||
UserDetailsForm,
|
||||
} from "./forms";
|
||||
import { SessionProps, useSession, withSession } from "./session";
|
||||
import StandardLayout from "./standard-layout";
|
||||
import Steps from "./steps";
|
||||
import { useUser } from "./user-provider";
|
||||
|
||||
type StepName = "eventDetails" | "options" | "userDetails";
|
||||
|
||||
|
@ -37,7 +37,7 @@ const required = <T,>(v: T | undefined): T => {
|
|||
const initialNewEventData: NewEventData = { currentStep: 0 };
|
||||
const sessionStorageKey = "newEventFormData";
|
||||
|
||||
export interface CreatePollPageProps extends SessionProps {
|
||||
export interface CreatePollPageProps {
|
||||
title?: string;
|
||||
location?: string;
|
||||
description?: string;
|
||||
|
@ -54,7 +54,7 @@ const Page: NextPage<CreatePollPageProps> = ({
|
|||
|
||||
const router = useRouter();
|
||||
|
||||
const session = useSession();
|
||||
const session = useUser();
|
||||
|
||||
const [persistedFormData, setPersistedFormData] =
|
||||
useSessionStorage<NewEventData>(sessionStorageKey, {
|
||||
|
@ -228,4 +228,4 @@ const Page: NextPage<CreatePollPageProps> = ({
|
|||
);
|
||||
};
|
||||
|
||||
export default withSession(Page);
|
||||
export default Page;
|
||||
|
|
|
@ -17,7 +17,7 @@ import NameInput from "../name-input";
|
|||
import TruncatedLinkify from "../poll/truncated-linkify";
|
||||
import UserAvatar from "../poll/user-avatar";
|
||||
import { usePoll } from "../poll-context";
|
||||
import { isUnclaimed, useSession } from "../session";
|
||||
import { isUnclaimed, useUser } from "../user-provider";
|
||||
|
||||
interface CommentForm {
|
||||
authorName: string;
|
||||
|
@ -68,7 +68,7 @@ const Discussion: React.VoidFunctionComponent = () => {
|
|||
},
|
||||
});
|
||||
|
||||
const session = useSession();
|
||||
const session = useUser();
|
||||
|
||||
const { register, reset, control, handleSubmit, formState } =
|
||||
useForm<CommentForm>({
|
||||
|
|
|
@ -15,8 +15,8 @@ import { GetPollApiResponse } from "@/utils/trpc/types";
|
|||
import { useDayjs } from "../utils/dayjs";
|
||||
import ErrorPage from "./error-page";
|
||||
import { useParticipants } from "./participants-provider";
|
||||
import { useSession } from "./session";
|
||||
import { useRequiredContext } from "./use-required-context";
|
||||
import { useUser } from "./user-provider";
|
||||
|
||||
type PollContextValue = {
|
||||
userAlreadyVoted: boolean;
|
||||
|
@ -61,7 +61,7 @@ export const PollContextProvider: React.VoidFunctionComponent<{
|
|||
const { t } = useTranslation("app");
|
||||
const { participants } = useParticipants();
|
||||
const [isDeleted, setDeleted] = React.useState(false);
|
||||
const { user } = useSession();
|
||||
const { user } = useUser();
|
||||
const [targetTimeZone, setTargetTimeZone] =
|
||||
React.useState(getBrowserTimeZone);
|
||||
|
||||
|
|
|
@ -28,8 +28,8 @@ import { useTouchBeacon } from "./poll/use-touch-beacon";
|
|||
import { UserAvatarProvider } from "./poll/user-avatar";
|
||||
import VoteIcon from "./poll/vote-icon";
|
||||
import { usePoll } from "./poll-context";
|
||||
import { useSession } from "./session";
|
||||
import Sharing from "./sharing";
|
||||
import { useUser } from "./user-provider";
|
||||
|
||||
const PollPage: NextPage = () => {
|
||||
const { poll, urlId, admin } = usePoll();
|
||||
|
@ -40,7 +40,7 @@ const PollPage: NextPage = () => {
|
|||
|
||||
const { t } = useTranslation("app");
|
||||
|
||||
const session = useSession();
|
||||
const session = useUser();
|
||||
|
||||
const queryClient = trpc.useContext();
|
||||
const plausible = usePlausible();
|
||||
|
|
|
@ -6,7 +6,7 @@ import CompactButton from "@/components/compact-button";
|
|||
import Pencil from "@/components/icons/pencil-alt.svg";
|
||||
import Trash from "@/components/icons/trash.svg";
|
||||
import { usePoll } from "@/components/poll-context";
|
||||
import { useSession } from "@/components/session";
|
||||
import { useUser } from "@/components/user-provider";
|
||||
|
||||
import { ParticipantFormSubmitted } from "../types";
|
||||
import { useDeleteParticipantModal } from "../use-delete-participant-modal";
|
||||
|
@ -108,7 +108,7 @@ const ParticipantRow: React.VoidFunctionComponent<ParticipantRowProps> = ({
|
|||
|
||||
const confirmDeleteParticipant = useDeleteParticipantModal();
|
||||
|
||||
const session = useSession();
|
||||
const session = useUser();
|
||||
const { poll, getVote, options } = usePoll();
|
||||
|
||||
const isYou = session.user && session.ownsObject(participant) ? true : false;
|
||||
|
|
|
@ -18,8 +18,8 @@ import { Button } from "../button";
|
|||
import { styleMenuItem } from "../menu-styles";
|
||||
import NameInput from "../name-input";
|
||||
import { useParticipants } from "../participants-provider";
|
||||
import { isUnclaimed, useSession } from "../session";
|
||||
import TimeZonePicker from "../time-zone-picker";
|
||||
import { isUnclaimed, useUser } from "../user-provider";
|
||||
import GroupedOptions from "./mobile-poll/grouped-options";
|
||||
import {
|
||||
normalizeVotes,
|
||||
|
@ -50,7 +50,7 @@ const MobilePoll: React.VoidFunctionComponent = () => {
|
|||
const { participants } = useParticipants();
|
||||
const { timeZone } = poll;
|
||||
|
||||
const session = useSession();
|
||||
const session = useUser();
|
||||
|
||||
const form = useForm<ParticipantForm>({
|
||||
defaultValues: {
|
||||
|
|
|
@ -2,7 +2,7 @@ import { usePlausible } from "next-plausible";
|
|||
|
||||
import { trpc } from "../../utils/trpc";
|
||||
import { usePoll } from "../poll-context";
|
||||
import { useSession } from "../session";
|
||||
import { useUser } from "../user-provider";
|
||||
import { ParticipantForm } from "./types";
|
||||
|
||||
export const normalizeVotes = (
|
||||
|
@ -17,7 +17,7 @@ export const normalizeVotes = (
|
|||
|
||||
export const useAddParticipantMutation = () => {
|
||||
const queryClient = trpc.useContext();
|
||||
const session = useSession();
|
||||
const session = useUser();
|
||||
const plausible = usePlausible();
|
||||
|
||||
return trpc.useMutation(["polls.participants.add"], {
|
||||
|
|
|
@ -12,10 +12,10 @@ 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";
|
||||
import { useUser } from "./user-provider";
|
||||
|
||||
export const Profile: React.VoidFunctionComponent = () => {
|
||||
const { user } = useSession();
|
||||
const { user } = useUser();
|
||||
const { dayjs } = useDayjs();
|
||||
|
||||
const { t } = useTranslation("app");
|
||||
|
|
|
@ -6,8 +6,8 @@ import { useForm } from "react-hook-form";
|
|||
import { requiredString, validEmail } from "../../utils/form-validation";
|
||||
import { trpc } from "../../utils/trpc";
|
||||
import { Button } from "../button";
|
||||
import { useSession } from "../session";
|
||||
import { TextInput } from "../text-input";
|
||||
import { useUser } from "../user-provider";
|
||||
|
||||
export interface UserDetailsProps {
|
||||
userId: string;
|
||||
|
@ -30,7 +30,7 @@ export const UserDetails: React.VoidFunctionComponent<UserDetailsProps> = ({
|
|||
defaultValues: { name, email },
|
||||
});
|
||||
|
||||
const { refresh } = useSession();
|
||||
const { refresh } = useUser();
|
||||
|
||||
const changeName = trpc.useMutation("user.changeName", {
|
||||
onSuccess: () => {
|
||||
|
|
|
@ -1,117 +0,0 @@
|
|||
import { IronSessionData } from "iron-session";
|
||||
import React from "react";
|
||||
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<IronSessionData["user"]>;
|
||||
|
||||
export type SessionProps = {
|
||||
user: UserSessionData;
|
||||
};
|
||||
|
||||
type ParticipantOrComment = {
|
||||
userId: string | null;
|
||||
};
|
||||
|
||||
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;
|
||||
refresh: () => void;
|
||||
ownsObject: (obj: ParticipantOrComment) => boolean;
|
||||
isLoading: boolean;
|
||||
};
|
||||
|
||||
export const SessionContext =
|
||||
React.createContext<SessionContextValue | null>(null);
|
||||
|
||||
SessionContext.displayName = "SessionContext";
|
||||
|
||||
export const SessionProvider: React.VoidFunctionComponent<{
|
||||
children?: React.ReactNode;
|
||||
}> = ({ children }) => {
|
||||
const queryClient = trpc.useContext();
|
||||
const { data: user, refetch, isLoading } = trpc.useQuery(["session.get"]);
|
||||
|
||||
const logout = trpc.useMutation(["session.destroy"], {
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries(["session.get"]);
|
||||
},
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
return <FullPageLoader>Loading user…</FullPageLoader>;
|
||||
}
|
||||
|
||||
const sessionData: SessionContextValue = {
|
||||
user: {
|
||||
...user,
|
||||
shortName:
|
||||
// try to get the first name in the event
|
||||
// that the user entered a full name
|
||||
user.isGuest
|
||||
? user.id.substring(0, 10)
|
||||
: user.name.length > 12 && user.name.indexOf(" ") !== -1
|
||||
? user.name.substring(0, user.name.indexOf(" "))
|
||||
: user.name,
|
||||
},
|
||||
refresh: () => {
|
||||
refetch();
|
||||
},
|
||||
isLoading,
|
||||
logout: () => {
|
||||
toast.promise(logout.mutateAsync(), {
|
||||
loading: "Logging out…",
|
||||
success: "Logged out",
|
||||
error: "Failed to log out",
|
||||
});
|
||||
},
|
||||
ownsObject: (obj) => {
|
||||
return obj.userId === user.id;
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<SessionContext.Provider value={sessionData}>
|
||||
{children}
|
||||
</SessionContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useSession = () => {
|
||||
return useRequiredContext(SessionContext);
|
||||
};
|
||||
|
||||
export const withSession = <P extends SessionProps>(
|
||||
component: React.ComponentType<P>,
|
||||
) => {
|
||||
const ComposedComponent: React.VoidFunctionComponent<P> = (props: P) => {
|
||||
const Component = component;
|
||||
return (
|
||||
<SessionProvider>
|
||||
<Component {...props} />
|
||||
</SessionProvider>
|
||||
);
|
||||
};
|
||||
ComposedComponent.displayName = component.displayName;
|
||||
return ComposedComponent;
|
||||
};
|
||||
|
||||
export const isUnclaimed = (obj: ParticipantOrComment) => !obj.userId;
|
|
@ -27,7 +27,7 @@ import { useModal } from "./modal";
|
|||
import ModalProvider, { useModalContext } from "./modal/modal-provider";
|
||||
import Popover from "./popover";
|
||||
import Preferences from "./preferences";
|
||||
import { useSession } from "./session";
|
||||
import { useUser } from "./user-provider";
|
||||
|
||||
const HomeLink = () => {
|
||||
return (
|
||||
|
@ -40,7 +40,7 @@ const HomeLink = () => {
|
|||
const MobileNavigation: React.VoidFunctionComponent<{
|
||||
openLoginModal: () => void;
|
||||
}> = ({ openLoginModal }) => {
|
||||
const { user } = useSession();
|
||||
const { user } = useUser();
|
||||
const { t } = useTranslation(["common", "app"]);
|
||||
return (
|
||||
<div
|
||||
|
@ -152,7 +152,7 @@ const AppMenu: React.VoidFunctionComponent<{ className?: string }> = ({
|
|||
const UserDropdown: React.VoidFunctionComponent<
|
||||
DropdownProps & { openLoginModal: () => void }
|
||||
> = ({ children, openLoginModal, ...forwardProps }) => {
|
||||
const { logout, user } = useSession();
|
||||
const { logout, user } = useUser();
|
||||
const { t } = useTranslation(["common", "app"]);
|
||||
const modalContext = useModalContext();
|
||||
if (!user) {
|
||||
|
@ -243,7 +243,7 @@ const UserDropdown: React.VoidFunctionComponent<
|
|||
const StandardLayout: React.VoidFunctionComponent<{
|
||||
children?: React.ReactNode;
|
||||
}> = ({ children, ...rest }) => {
|
||||
const { user } = useSession();
|
||||
const { user } = useUser();
|
||||
const { t } = useTranslation(["common", "app"]);
|
||||
const [loginModal, openLoginModal] = useModal({
|
||||
footer: null,
|
||||
|
|
109
src/components/user-provider.tsx
Normal file
109
src/components/user-provider.tsx
Normal file
|
@ -0,0 +1,109 @@
|
|||
import { useTranslation } from "next-i18next";
|
||||
import React from "react";
|
||||
|
||||
import { UserSession } from "@/utils/auth";
|
||||
|
||||
import { trpcNext } from "../utils/trpc";
|
||||
import { useRequiredContext } from "./use-required-context";
|
||||
|
||||
export const UserContext =
|
||||
React.createContext<{
|
||||
user: UserSession & { shortName: string };
|
||||
refresh: () => void;
|
||||
logout: () => Promise<void>;
|
||||
ownsObject: (obj: { userId: string | null }) => boolean;
|
||||
} | null>(null);
|
||||
|
||||
export const useUser = () => {
|
||||
return useRequiredContext(UserContext, "UserContext");
|
||||
};
|
||||
|
||||
export const useAuthenticatedUser = () => {
|
||||
const { user, ...rest } = useRequiredContext(UserContext, "UserContext");
|
||||
if (user.isGuest) {
|
||||
throw new Error("Forget to prefetch user identity");
|
||||
}
|
||||
|
||||
return { user, ...rest };
|
||||
};
|
||||
|
||||
export const IfAuthenticated = (props: { children?: React.ReactNode }) => {
|
||||
const { user } = useUser();
|
||||
if (user.isGuest) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <>{props.children}</>;
|
||||
};
|
||||
|
||||
export const IfGuest = (props: { children?: React.ReactNode }) => {
|
||||
const { user } = useUser();
|
||||
if (!user.isGuest) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <>{props.children}</>;
|
||||
};
|
||||
|
||||
export const UserProvider = (props: { children?: React.ReactNode }) => {
|
||||
const { t } = useTranslation("app");
|
||||
|
||||
const { data: user, refetch } = trpcNext.whoami.get.useQuery();
|
||||
const logout = trpcNext.whoami.destroy.useMutation();
|
||||
|
||||
const shortName = user
|
||||
? user.isGuest === false
|
||||
? user.name
|
||||
: `${t("guest")}-${user.id.substring(user.id.length - 4)}`
|
||||
: t("guest");
|
||||
|
||||
if (!user) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<UserContext.Provider
|
||||
value={{
|
||||
user: { ...user, shortName },
|
||||
refresh: refetch,
|
||||
ownsObject: ({ userId }) => {
|
||||
if (userId && user.id === userId) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
logout: async () => {
|
||||
await logout.mutateAsync();
|
||||
refetch();
|
||||
},
|
||||
}}
|
||||
>
|
||||
{props.children}
|
||||
</UserContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
type ParticipantOrComment = {
|
||||
userId: string | null;
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
export const withSession = <P extends {} = {}>(
|
||||
component: React.ComponentType<P>,
|
||||
) => {
|
||||
const ComposedComponent: React.VoidFunctionComponent<P> = (props: P) => {
|
||||
const Component = component;
|
||||
return (
|
||||
<UserProvider>
|
||||
<Component {...props} />
|
||||
</UserProvider>
|
||||
);
|
||||
};
|
||||
ComposedComponent.displayName = `withUser(${component.displayName})`;
|
||||
return ComposedComponent;
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated Stop using this function. All object
|
||||
*/
|
||||
export const isUnclaimed = (obj: ParticipantOrComment) => !obj.userId;
|
|
@ -49,10 +49,7 @@ const MyApp: NextPage<AppProps> = ({ Component, pageProps }) => {
|
|||
customDomain={process.env.NEXT_PUBLIC_PLAUSIBLE_DOMAIN}
|
||||
trackOutboundLinks={true}
|
||||
selfHosted={true}
|
||||
enabled={
|
||||
typeof window !== undefined &&
|
||||
!!process.env.NEXT_PUBLIC_PLAUSIBLE_DOMAIN
|
||||
}
|
||||
enabled={!!process.env.NEXT_PUBLIC_PLAUSIBLE_DOMAIN}
|
||||
>
|
||||
<DefaultSeo
|
||||
openGraph={{
|
||||
|
|
|
@ -2,10 +2,11 @@ import { GetServerSideProps } from "next";
|
|||
|
||||
import CreatePoll from "@/components/create-poll";
|
||||
|
||||
import { withSession } from "../components/user-provider";
|
||||
import { withSessionSsr } from "../utils/auth";
|
||||
import { withPageTranslations } from "../utils/with-page-translations";
|
||||
|
||||
export default CreatePoll;
|
||||
export default withSession(CreatePoll);
|
||||
|
||||
export const getServerSideProps: GetServerSideProps = withSessionSsr(
|
||||
withPageTranslations(["common", "app"]),
|
||||
|
|
|
@ -6,10 +6,10 @@ import React from "react";
|
|||
import FullPageLoader from "@/components/full-page-loader";
|
||||
import PollPage from "@/components/poll";
|
||||
import { PollContextProvider } from "@/components/poll-context";
|
||||
import { withSession } from "@/components/session";
|
||||
|
||||
import { ParticipantsProvider } from "../components/participants-provider";
|
||||
import StandardLayout from "../components/standard-layout";
|
||||
import { withSession } from "../components/user-provider";
|
||||
import { withSessionSsr } from "../utils/auth";
|
||||
import { trpc } from "../utils/trpc";
|
||||
import { withPageTranslations } from "../utils/with-page-translations";
|
||||
|
|
|
@ -3,8 +3,8 @@ import { NextPage } from "next";
|
|||
import { withSessionSsr } from "@/utils/auth";
|
||||
|
||||
import { Profile } from "../components/profile";
|
||||
import { withSession } from "../components/session";
|
||||
import StandardLayout from "../components/standard-layout";
|
||||
import { withSession } from "../components/user-provider";
|
||||
import { withPageTranslations } from "../utils/with-page-translations";
|
||||
|
||||
const Page: NextPage = () => {
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
import { z } from "zod";
|
||||
|
||||
import { prisma } from "~/prisma/db";
|
||||
|
||||
import { createRouter } from "../createRouter";
|
||||
import { mergeRouters, publicProcedure, router } from "../trpc";
|
||||
import { mergeRouters, router } from "../trpc";
|
||||
import { login } from "./login";
|
||||
import { polls } from "./polls";
|
||||
import { session } from "./session";
|
||||
import { user } from "./user";
|
||||
import { whoami } from "./whoami";
|
||||
|
||||
const legacyRouter = createRouter()
|
||||
.merge("user.", user)
|
||||
|
@ -18,24 +15,7 @@ const legacyRouter = createRouter()
|
|||
export const appRouter = mergeRouters(
|
||||
legacyRouter.interop(),
|
||||
router({
|
||||
p: router({
|
||||
touch: publicProcedure
|
||||
.input(
|
||||
z.object({
|
||||
pollId: z.string(),
|
||||
}),
|
||||
)
|
||||
.mutation(async ({ input }) => {
|
||||
await prisma.poll.update({
|
||||
where: {
|
||||
id: input.pollId,
|
||||
},
|
||||
data: {
|
||||
touchedAt: new Date(),
|
||||
},
|
||||
});
|
||||
}),
|
||||
}),
|
||||
whoami,
|
||||
}),
|
||||
);
|
||||
|
||||
|
|
30
src/server/routers/whoami.ts
Normal file
30
src/server/routers/whoami.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
import { prisma } from "~/prisma/db";
|
||||
|
||||
import { createGuestUser, UserSession } from "../../utils/auth";
|
||||
import { publicProcedure, router } from "../trpc";
|
||||
|
||||
export const whoami = router({
|
||||
get: publicProcedure.query(async ({ ctx }): Promise<UserSession> => {
|
||||
if (ctx.user.isGuest) {
|
||||
return { isGuest: true, id: ctx.user.id };
|
||||
}
|
||||
|
||||
const user = await prisma.user.findUnique({
|
||||
select: { id: true, name: true, email: true },
|
||||
where: { id: ctx.user.id },
|
||||
});
|
||||
|
||||
if (user === null) {
|
||||
const guestUser = await createGuestUser();
|
||||
ctx.session.user = guestUser;
|
||||
await ctx.session.save();
|
||||
|
||||
return guestUser;
|
||||
}
|
||||
|
||||
return { isGuest: false, ...user };
|
||||
}),
|
||||
destroy: publicProcedure.mutation(async ({ ctx }) => {
|
||||
ctx.session.destroy();
|
||||
}),
|
||||
});
|
|
@ -9,6 +9,7 @@ import { GetServerSideProps, NextApiHandler } from "next";
|
|||
|
||||
import { prisma } from "~/prisma/db";
|
||||
|
||||
import { createSSGHelperFromContext } from "../server/context";
|
||||
import { randomid } from "./nanoid";
|
||||
|
||||
const sessionOptions: IronSessionOptions = {
|
||||
|
@ -20,12 +21,42 @@ const sessionOptions: IronSessionOptions = {
|
|||
ttl: 0, // basically forever
|
||||
};
|
||||
|
||||
export type RegisteredUserSession = {
|
||||
isGuest: false;
|
||||
id: string;
|
||||
name: string;
|
||||
email: string;
|
||||
};
|
||||
|
||||
export type GuestUserSession = {
|
||||
isGuest: true;
|
||||
id: string;
|
||||
};
|
||||
|
||||
export type UserSession = GuestUserSession | RegisteredUserSession;
|
||||
|
||||
const setUser = async (session: IronSession) => {
|
||||
if (!session.user) {
|
||||
session.user = await createGuestUser();
|
||||
await session.save();
|
||||
}
|
||||
|
||||
if (!session.user.isGuest) {
|
||||
// Check registered user still exists
|
||||
const user = await prisma.user.findUnique({
|
||||
where: { id: session.user.id },
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
session.user = await createGuestUser();
|
||||
await session.save();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export function withSessionRoute(handler: NextApiHandler) {
|
||||
return withIronSessionApiRoute(async (req, res) => {
|
||||
if (!req.session.user) {
|
||||
req.session.user = await createGuestUser();
|
||||
await req.session.save();
|
||||
}
|
||||
await setUser(req.session);
|
||||
return await handler(req, res);
|
||||
}, sessionOptions);
|
||||
}
|
||||
|
@ -33,14 +64,23 @@ export function withSessionRoute(handler: NextApiHandler) {
|
|||
export function withSessionSsr(handler: GetServerSideProps) {
|
||||
return withIronSessionSsr(async (context) => {
|
||||
const { req } = context;
|
||||
if (!req.session.user) {
|
||||
req.session.user = await createGuestUser();
|
||||
await req.session.save();
|
||||
}
|
||||
|
||||
await setUser(req.session);
|
||||
|
||||
const ssg = await createSSGHelperFromContext(context);
|
||||
await ssg.whoami.get.prefetch();
|
||||
|
||||
const res = await handler(context);
|
||||
|
||||
if ("props" in res) {
|
||||
return { ...res, props: { ...res.props, user: req.session.user } };
|
||||
return {
|
||||
...res,
|
||||
props: {
|
||||
...res.props,
|
||||
user: req.session.user,
|
||||
trpcState: ssg.dehydrate(),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return res;
|
||||
|
|
|
@ -18,7 +18,6 @@ test("should be able to vote and comment on a poll", async ({ page }) => {
|
|||
await page.locator("data-testid=vote-selector >> nth=2").click();
|
||||
await page.click("text='Save'");
|
||||
await expect(page.locator("text='Test user'")).toBeVisible();
|
||||
await expect(page.locator("text=Guest")).toBeVisible();
|
||||
await expect(
|
||||
page.locator("data-testid=participant-row >> nth=4").locator("text=You"),
|
||||
).toBeVisible();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue