diff --git a/apps/web/src/components/invite-dialog.tsx b/apps/web/src/components/invite-dialog.tsx index cb98c2bd2..c1cb62d10 100644 --- a/apps/web/src/components/invite-dialog.tsx +++ b/apps/web/src/components/invite-dialog.tsx @@ -15,8 +15,6 @@ import { useCopyToClipboard } from "react-use"; import { useParticipants } from "@/components/participants-provider"; import { Trans } from "@/components/trans"; import { usePoll } from "@/contexts/poll"; -import { shortUrl } from "@/utils/absolute-url"; -import { isSelfHosted } from "@/utils/constants"; export const InviteDialog = () => { const { participants } = useParticipants(); @@ -31,10 +29,6 @@ export const InviteDialog = () => { } }, [state]); - const inviteLink = isSelfHosted - ? window.location.origin + `/invite/${poll?.id}` - : shortUrl(`/invite/${poll?.id}`); - const [didCopy, setDidCopy] = React.useState(false); return ( @@ -72,7 +66,7 @@ export const InviteDialog = () => {
diff --git a/apps/web/src/components/layouts/standard-layout.tsx b/apps/web/src/components/layouts/standard-layout.tsx index 8a7492c1f..e2e1ac0f0 100644 --- a/apps/web/src/components/layouts/standard-layout.tsx +++ b/apps/web/src/components/layouts/standard-layout.tsx @@ -23,11 +23,10 @@ import { UserDropdown } from "@/components/user-dropdown"; import { IfCloudHosted } from "@/contexts/environment"; import { IfFreeUser } from "@/contexts/plan"; import { appVersion, isFeedbackEnabled } from "@/utils/constants"; -import { ConnectedDayjsProvider } from "@/utils/dayjs"; import { IconComponent, NextPageWithLayout } from "../../types"; import ModalProvider from "../modal/modal-provider"; -import { IfGuest, UserProvider } from "../user-provider"; +import { IfGuest } from "../user-provider"; const NavMenuItem = ({ href, @@ -181,49 +180,45 @@ export const StandardLayout: React.FunctionComponent<{ }> = ({ children, hideNav, ...rest }) => { const key = hideNav ? "no-nav" : "nav"; return ( - - - - -
- - {!hideNav ? : null} - - - - {children} - - - {appVersion ? ( -
- - {`${appVersion}`} - -
- ) : null} + + +
+ + {!hideNav ? : null} + + + + {children} + + + {appVersion ? ( +
+ + {`${appVersion}`} +
- {isFeedbackEnabled ? ( - <> - - - - ) : null} - - - + ) : null} +
+ {isFeedbackEnabled ? ( + <> + + + + ) : null} +
); }; diff --git a/apps/web/src/pages/_app.tsx b/apps/web/src/pages/_app.tsx index 0b9f7eebc..8c14dea73 100644 --- a/apps/web/src/pages/_app.tsx +++ b/apps/web/src/pages/_app.tsx @@ -9,11 +9,14 @@ import { AppProps } from "next/app"; import { Inter } from "next/font/google"; import Head from "next/head"; import Script from "next/script"; -import { SessionProvider } from "next-auth/react"; +import { SessionProvider, signIn, useSession } from "next-auth/react"; import { appWithTranslation } from "next-i18next"; import { DefaultSeo } from "next-seo"; +import React from "react"; import Maintenance from "@/components/maintenance"; +import { UserProvider } from "@/components/user-provider"; +import { ConnectedDayjsProvider } from "@/utils/dayjs"; import { trpc } from "@/utils/trpc/client"; import * as nextI18nNextConfig from "../../next-i18next.config.js"; @@ -29,12 +32,30 @@ type AppPropsWithLayout = AppProps & { Component: NextPageWithLayout; }; +const Auth = ({ children }: { children: React.ReactNode }) => { + const session = useSession(); + const isAuthenticated = !!session.data?.user.email; + + React.useEffect(() => { + if (!isAuthenticated) { + signIn(); + } + }, [isAuthenticated]); + + if (isAuthenticated) { + return <>{children}; + } + + return null; +}; + const MyApp: NextPage = ({ Component, pageProps }) => { if (process.env.NEXT_PUBLIC_MAINTENANCE_MODE === "1") { return ; } const getLayout = Component.getLayout ?? ((page) => page); + const children = ; return ( @@ -83,7 +104,15 @@ const MyApp: NextPage = ({ Component, pageProps }) => { } `} - {getLayout()} + + + {Component.isAuthRequired ? ( + {getLayout(children)} + ) : ( + getLayout(children) + )} + + diff --git a/apps/web/src/pages/invite/[urlId].tsx b/apps/web/src/pages/invite/[urlId].tsx index 2c3845de6..ef5110d1c 100644 --- a/apps/web/src/pages/invite/[urlId].tsx +++ b/apps/web/src/pages/invite/[urlId].tsx @@ -13,12 +13,11 @@ import { Poll } from "@/components/poll"; import { LegacyPollContextProvider } from "@/components/poll/poll-context-provider"; import { Trans } from "@/components/trans"; import { UserDropdown } from "@/components/user-dropdown"; -import { UserProvider, useUser } from "@/components/user-provider"; +import { useUser } from "@/components/user-provider"; import { VisibilityProvider } from "@/components/visibility"; import { PermissionsContext } from "@/contexts/permissions"; import { usePoll } from "@/contexts/poll"; import { absoluteUrl } from "@/utils/absolute-url"; -import { ConnectedDayjsProvider } from "@/utils/dayjs"; import { trpc } from "@/utils/trpc/client"; import { getStaticTranslations } from "@/utils/with-page-translations"; @@ -118,62 +117,58 @@ const Page = ({ id, title, user }: PageProps) => { ], }} /> - - - - - -
-
+ + +
+ +
+
+ + ), + }} /> - - -
- -
-
- - ), - }} - /> -
-
- - - - - +
+
+ + + ); }; diff --git a/apps/web/src/pages/new.tsx b/apps/web/src/pages/new.tsx index 2b6928bcd..a16caa18f 100644 --- a/apps/web/src/pages/new.tsx +++ b/apps/web/src/pages/new.tsx @@ -3,6 +3,7 @@ import { useTranslation } from "next-i18next"; import { CreatePoll } from "@/components/create-poll"; import { getStandardLayout } from "@/components/layouts/standard-layout"; +import { isSelfHosted } from "@/utils/constants"; import { NextPageWithLayout } from "../types"; import { getStaticTranslations } from "../utils/with-page-translations"; @@ -95,6 +96,7 @@ const Page: NextPageWithLayout = () => { }; Page.getLayout = getStandardLayout; +Page.isAuthRequired = isSelfHosted; export default Page; diff --git a/apps/web/src/pages/poll/[urlId].tsx b/apps/web/src/pages/poll/[urlId].tsx index 0a2db775b..313f9d8b2 100644 --- a/apps/web/src/pages/poll/[urlId].tsx +++ b/apps/web/src/pages/poll/[urlId].tsx @@ -10,6 +10,7 @@ import { RegisterLink } from "@/components/register-link"; import { useUser } from "@/components/user-provider"; import { usePoll } from "@/contexts/poll"; import { NextPageWithLayout } from "@/types"; +import { isSelfHosted } from "@/utils/constants"; import { getStaticTranslations } from "@/utils/with-page-translations"; const GuestPollAlert = () => { @@ -58,6 +59,7 @@ const Page: NextPageWithLayout = () => { }; Page.getLayout = getPollLayout; +Page.isAuthRequired = isSelfHosted; export const getStaticPaths = async () => { return { diff --git a/apps/web/src/pages/polls.tsx b/apps/web/src/pages/polls.tsx index 9eff9a6f4..da92b3611 100644 --- a/apps/web/src/pages/polls.tsx +++ b/apps/web/src/pages/polls.tsx @@ -23,6 +23,7 @@ import { PollStatusBadge } from "@/components/poll-status"; import { Skeleton } from "@/components/skeleton"; import { Trans } from "@/components/trans"; import { NextPageWithLayout } from "@/types"; +import { isSelfHosted } from "@/utils/constants"; import { useDayjs } from "@/utils/dayjs"; import { trpc } from "@/utils/trpc/client"; import { getStaticTranslations } from "@/utils/with-page-translations"; @@ -187,6 +188,7 @@ const Page: NextPageWithLayout = () => { }; Page.getLayout = getStandardLayout; +Page.isAuthRequired = isSelfHosted; export default Page; diff --git a/apps/web/src/pages/settings/billing.tsx b/apps/web/src/pages/settings/billing.tsx index 0f27e59ff..9aac451a7 100644 --- a/apps/web/src/pages/settings/billing.tsx +++ b/apps/web/src/pages/settings/billing.tsx @@ -282,6 +282,7 @@ const Page: NextPageWithLayout = () => { Page.getLayout = getProfileLayout; export const getStaticProps: GetStaticProps = async (ctx) => { + // This page is only available on the hosted version if (isSelfHosted) { return { notFound: true, diff --git a/apps/web/src/pages/settings/profile.tsx b/apps/web/src/pages/settings/profile.tsx index 38c4fbe40..3617cd34f 100644 --- a/apps/web/src/pages/settings/profile.tsx +++ b/apps/web/src/pages/settings/profile.tsx @@ -71,6 +71,7 @@ const Page: NextPageWithLayout = () => { }; Page.getLayout = getProfileLayout; +Page.isAuthRequired = true; export const getStaticProps = getStaticTranslations; diff --git a/apps/web/src/types.ts b/apps/web/src/types.ts index 404c4a8e2..47cb327a8 100644 --- a/apps/web/src/types.ts +++ b/apps/web/src/types.ts @@ -10,6 +10,7 @@ export type PropsOf = TTag extends React.ElementType // eslint-disable-next-line @typescript-eslint/ban-types export type NextPageWithLayout

= NextPage & { getLayout?: (page: React.ReactElement) => React.ReactNode; + isAuthRequired?: boolean; }; // eslint-disable-next-line @typescript-eslint/ban-types diff --git a/packages/backend/trpc/routers/polls.ts b/packages/backend/trpc/routers/polls.ts index 885fe6946..0cbd3b321 100644 --- a/packages/backend/trpc/routers/polls.ts +++ b/packages/backend/trpc/routers/polls.ts @@ -16,7 +16,6 @@ import { router, } from "../trpc"; import { comments } from "./polls/comments"; -import { demo } from "./polls/demo"; import { options } from "./polls/options"; import { participants } from "./polls/participants"; @@ -42,7 +41,6 @@ const getPollIdFromAdminUrlId = async (urlId: string) => { }; export const polls = router({ - demo, participants, comments, options, @@ -390,11 +388,12 @@ export const polls = router({ message: "Poll not found", }); } + const inviteLink = ctx.shortUrl(`/invite/${res.id}`); if (ctx.user.id === res.userId || res.adminUrlId === input.adminToken) { - return res; + return { ...res, inviteLink }; } else { - return { ...res, adminUrlId: "" }; + return { ...res, adminUrlId: "", inviteLink }; } }), transfer: possiblyPublicProcedure diff --git a/packages/backend/trpc/routers/polls/demo.ts b/packages/backend/trpc/routers/polls/demo.ts deleted file mode 100644 index 57125ed74..000000000 --- a/packages/backend/trpc/routers/polls/demo.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { prisma, VoteType } from "@rallly/database"; -import dayjs from "dayjs"; - -import { nanoid } from "../../../utils/nanoid"; -import { possiblyPublicProcedure, router } from "../../trpc"; - -const participantData: Array<{ name: string; votes: VoteType[] }> = [ - { - name: "Reed", - votes: ["yes", "no", "yes", "no"], - }, - { - name: "Susan", - votes: ["yes", "yes", "yes", "no"], - }, - { - name: "Johnny", - votes: ["no", "no", "yes", "yes"], - }, - { - name: "Ben", - votes: ["yes", "yes", "yes", "yes"], - }, -]; - -const optionValues = ["2022-12-14", "2022-12-15", "2022-12-16", "2022-12-17"]; - -export const demo = router({ - create: possiblyPublicProcedure.mutation(async () => { - const adminUrlId = nanoid(); - const demoUser = { name: "John Example", email: "noreply@rallly.co" }; - - const options: Array<{ start: Date; id: string }> = []; - - for (let i = 0; i < optionValues.length; i++) { - options.push({ id: await nanoid(), start: new Date(optionValues[i]) }); - } - - const participants: Array<{ - name: string; - id: string; - userId: string; - createdAt: Date; - }> = []; - - const votes: Array<{ - optionId: string; - participantId: string; - type: VoteType; - }> = []; - - for (let i = 0; i < participantData.length; i++) { - const { name, votes: participantVotes } = participantData[i]; - const participantId = await nanoid(); - participants.push({ - id: participantId, - name, - userId: "user-demo", - createdAt: dayjs() - .add(i * -1, "minutes") - .toDate(), - }); - - options.forEach((option, index) => { - votes.push({ - optionId: option.id, - participantId, - type: participantVotes[index], - }); - }); - } - - await prisma.poll.create({ - data: { - id: nanoid(), - title: "Lunch Meeting", - location: "Starbucks, 901 New York Avenue", - description: `Hey everyone, please choose the dates when you are available to meet for our monthly get together. Looking forward to see you all!`, - demo: true, - adminUrlId, - participantUrlId: nanoid(), - user: { - connectOrCreate: { - where: { - email: demoUser.email, - }, - create: demoUser, - }, - }, - options: { - createMany: { - data: options, - }, - }, - participants: { - createMany: { - data: participants, - }, - }, - votes: { - createMany: { - data: votes, - }, - }, - }, - }); - - return adminUrlId; - }), -});