diff --git a/apps/web/next.config.js b/apps/web/next.config.js index 7393ba932..e1849c0ee 100644 --- a/apps/web/next.config.js +++ b/apps/web/next.config.js @@ -10,7 +10,6 @@ const withBundleAnalyzer = require("@next/bundle-analyzer")({ /** @type {import('next').NextConfig} */ const nextConfig = { - output: "standalone", productionBrowserSourceMaps: true, transpilePackages: [ "@rallly/backend", diff --git a/apps/web/public/locales/en/app.json b/apps/web/public/locales/en/app.json index 9636e9617..b991a71c5 100644 --- a/apps/web/public/locales/en/app.json +++ b/apps/web/public/locales/en/app.json @@ -221,7 +221,6 @@ "integrations": "Integrations", "contacts": "Contacts", "unlockFeatures": "Unlock all Pro features.", - "back": "Back", "pollStatusAll": "All", "pollStatusLive": "Live", "pollStatusFinalized": "Finalized", @@ -238,5 +237,8 @@ "registrations": "Registrations", "inviteParticipantsDescription": "Copy and share the invite link to start gathering responses from your participants.", "inviteLink": "Invite Link", - "inviteParticipantLinkInfo": "Anyone with this link will be able to vote on your poll." + "inviteParticipantLinkInfo": "Anyone with this link will be able to vote on your poll.", + "accountNotLinkedTitle": "Your account cannot be linked to an existing user", + "accountNotLinkedDescription": "A user with this email already exists. Please log in using the original method.", + "or": "Or" } diff --git a/apps/web/public/static/microsoft.svg b/apps/web/public/static/microsoft.svg new file mode 100644 index 000000000..1f7397648 --- /dev/null +++ b/apps/web/public/static/microsoft.svg @@ -0,0 +1 @@ +MS-SymbolLockup \ No newline at end of file diff --git a/apps/web/src/app/[locale]/(auth)/login/login-form.tsx b/apps/web/src/app/[locale]/(auth)/login/login-form.tsx index 834044f29..161abd2ed 100644 --- a/apps/web/src/app/[locale]/(auth)/login/login-form.tsx +++ b/apps/web/src/app/[locale]/(auth)/login/login-form.tsx @@ -1,7 +1,8 @@ "use client"; +import { Alert, AlertDescription, AlertTitle } from "@rallly/ui/alert"; import { Button } from "@rallly/ui/button"; import { useQuery } from "@tanstack/react-query"; -import { UserIcon } from "lucide-react"; +import { AlertTriangleIcon, UserIcon } from "lucide-react"; import Image from "next/image"; import { useRouter, useSearchParams } from "next/navigation"; import { getProviders, signIn, useSession } from "next-auth/react"; @@ -21,6 +22,7 @@ const allowGuestAccess = !isSelfHosted; export function LoginForm() { const { t } = useTranslation(); + const searchParams = useSearchParams(); const { register, handleSubmit, getValues, formState, setError } = useForm<{ email: string; @@ -38,21 +40,13 @@ export function LoginForm() { const [email, setEmail] = React.useState(); const posthog = usePostHog(); const router = useRouter(); - const callbackUrl = (useSearchParams()?.get("callbackUrl") as string) ?? "/"; + const callbackUrl = searchParams?.get("callbackUrl") ?? "/"; + + const error = searchParams?.get("error"); const alternativeLoginMethods = React.useMemo(() => { const res: Array<{ login: () => void; icon: JSX.Element; name: string }> = []; - if (allowGuestAccess) { - res.push({ - login: () => { - router.push(callbackUrl); - }, - icon: , - name: t("continueAsGuest"), - }); - } - if (providers?.oidc) { res.push({ login: () => { @@ -78,6 +72,35 @@ export function LoginForm() { name: t("loginWith", { provider: providers.google.name }), }); } + + if (providers?.["azure-ad"]) { + res.push({ + login: () => { + signIn("azure-ad", { + callbackUrl, + }); + }, + icon: ( + Azure AD + ), + name: t("loginWith", { provider: "Microsoft" }), + }); + } + + if (allowGuestAccess) { + res.push({ + login: () => { + router.push(callbackUrl); + }, + icon: , + name: t("continueAsGuest"), + }); + } return res; }, [callbackUrl, providers, router, t]); @@ -148,7 +171,7 @@ export function LoginForm() { total: 2, })}

-
+
@@ -176,12 +199,35 @@ export function LoginForm() { variant="primary" className="" > - {t("continue")} + {t("loginWith", { + provider: t("email"), + })} + {error === "OAuthAccountNotLinked" ? ( + + + {t("accountNotLinkedTitle", { + defaultValue: + "Your account cannot be linked to an existing user", + })} + + + {t("accountNotLinkedDescription", { + defaultValue: + "A user with this email already exists. Please log in using the original method.", + })} + + + ) : null} {alternativeLoginMethods.length > 0 ? ( <> -
-
+
+
+ + {t("or", { defaultValue: "Or" })} + +
+
{alternativeLoginMethods.map((method, i) => (