Skip to content

Commit

Permalink
✨ Updated auth pages
Browse files Browse the repository at this point in the history
  • Loading branch information
lukevella committed Jan 20, 2025
1 parent 5d9606b commit dbfbfae
Show file tree
Hide file tree
Showing 69 changed files with 1,698 additions and 709 deletions.
35 changes: 26 additions & 9 deletions apps/web/public/locales/en/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
"12h": "12-hour",
"24h": "24-hour",
"addTimeOption": "Add time option",
"alreadyRegistered": "Already registered? <a>Login</a>",
"applyToAllDates": "Apply to all dates",
"areYouSure": "Are you sure?",
"cancel": "Cancel",
Expand Down Expand Up @@ -39,7 +38,6 @@
"location": "Location",
"locationPlaceholder": "Joe's Coffee Shop",
"login": "Login",
"loginWith": "Login with {provider}",
"logout": "Logout",
"manage": "Manage",
"mixedOptionsDescription": "You can't have both time and date options in the same poll. Which would you like to keep?",
Expand Down Expand Up @@ -75,11 +73,9 @@
"titlePlaceholder": "Monthly Meetup",
"today": "Today",
"userAlreadyExists": "A user with that email already exists",
"userNotFound": "A user with that email doesn't exist",
"validEmail": "Please enter a valid email",
"verificationCodeHelp": "Didn't get the email? Check your spam/junk.",
"verificationCodePlaceholder": "Enter your 6-digit code",
"verifyYourEmail": "Verify your email",
"startOfWeek": "Start of week",
"weekView": "Week view",
"wrongVerificationCode": "Your verification code is incorrect or has expired",
Expand Down Expand Up @@ -174,7 +170,6 @@
"duplicateTitleLabel": "Title",
"duplicateTitleDescription": "Hint: Give your new poll a unique title",
"upgrade": "Upgrade",
"continueAsGuest": "Continue as Guest",
"scrollLeft": "Scroll Left",
"scrollRight": "Scroll Right",
"shrink": "Shrink",
Expand All @@ -200,7 +195,6 @@
"hideScoresLabel": "Hide scores until after a participant has voted",
"continueAs": "Continue as",
"pageMovedDescription": "Redirecting to <a>{newUrl}</a>",
"notRegistered": "Don't have an account? <a>Register</a>",
"unlockFeatures": "Unlock all Pro features.",
"pollStatusFinalized": "Finalized",
"share": "Share",
Expand All @@ -213,7 +207,6 @@
"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.",
"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",
"autoTimeZone": "Automatic Time Zone Conversion",
Expand All @@ -234,7 +227,6 @@
"dangerZoneAccount": "Delete your account permanently. This action cannot be undone.",
"upgradePromptTitle": "Upgrade to Pro",
"upgradeOverlaySubtitle3": "Unlock these feature by upgrading to a Pro plan.",
"verificationCodeSentTo": "We sent a verification code to <b>{email}</b>",
"home": "Home",
"groupPoll": "Group Poll",
"groupPollDescription": "Share your availability with a group of people and find the best time to meet.",
Expand Down Expand Up @@ -289,5 +281,30 @@
"emailChangeRequestSentDescription": "To complete the change, please check your email for a verification link.",
"profileEmailAddress": "Email Address",
"profileEmailAddressDescription": "Your email address is used to log in to your account",
"emailAlreadyInUse": "This email address is already associated with another account. Please use a different email address."
"emailAlreadyInUse": "This email address is already associated with another account. Please use a different email address.",
"continueWith": "Continue with {provider}",
"continueWithProvider": "Continue with {{provider}}",
"loginFooter": "Don't have an account? <a>Sign up</a>",
"back": "Back",
"verifyEmail": "Verify your email",
"alreadyHaveAccount": "Already have an account? <a>Log in</a>",
"loginDescription": "Login to your account to continue",
"userNotFound": "A user with that email doesn't exist",
"loginTitle": "Welcome",
"registerTitle": "Create Your Account",
"registerDescription": "Streamline your scheduling process and save time",
"quickActionCreate": "Quick Create",
"quickActionsDescription": "Create a group poll without signing in. Login later to link it to your account.",
"quickCreateGroupPoll": "Create Group Poll",
"quickCreate": "Quick Create",
"quickCreateRecentlyCreated": "Recently Created",
"quickCreateWhyCreateAnAccount": "Why create an account?",
"quickCreateSecurePolls": "Store polls securely in your account",
"quickCreateGetNotifications": "Get email notifications notifications",
"quickCreateManagePollsFromAnyDevice": "Manage your polls from any device",
"registerVerifyTitle": "Finish Registering",
"registerVerifyDescription": "Check your email for the verification code",
"loginVerifyTitle": "Finish Logging In",
"loginVerifyDescription": "Check your email for the verification code",
"createAccount": "Create Account"
}
2 changes: 1 addition & 1 deletion apps/web/src/app/[locale]/(admin)/app-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export function GroupPollIcon({
"size-6 rounded": size === "xs",
"size-8 rounded-md": size === "sm",
"size-9 rounded-md": size === "md",
"size-10 rounded-lg": size === "lg",
"size-10 rounded-md": size === "lg",
},
)}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { useMutation } from "@tanstack/react-query";
import { useRouter } from "next/navigation";
import { useSession } from "next-auth/react";

import { Logo } from "@/components/logo";
import { OptimizedAvatarImage } from "@/components/optimized-avatar-image";
import { Skeleton } from "@/components/skeleton";
import { Trans } from "@/components/trans";
Expand Down Expand Up @@ -40,42 +39,37 @@ export const LoginPage = ({ magicLink, email }: PageProps) => {
const { data } = trpc.user.getByEmail.useQuery({ email });
const router = useRouter();
return (
<div className="flex h-screen flex-col items-center justify-center gap-4 p-4">
<div className="mb-6">
<Logo />
</div>

<div className="shadow-huge rounded-md bg-white p-4">
<div className="w-48 text-center">
<div className="mb-4 font-semibold">
<Trans i18nKey="continueAs" defaults="Continue as" />
</div>
<div className="flex flex-col items-center gap-2">
<OptimizedAvatarImage
src={data?.image ?? undefined}
name={data?.name ?? ""}
size="xl"
/>
<div className="text-center">
<div className="mb-1 h-6 font-medium">
{data?.name ?? <Skeleton className="inline-block h-5 w-16" />}
</div>
<div className="text-muted-foreground h-5 truncate text-sm">
{data?.email ?? (
<Skeleton className="inline-block h-full w-20" />
)}
</div>
<div className="flex h-full w-full flex-col items-center justify-center">
<div className="w-48 space-y-8 text-center">
<h1 className="text-xl font-bold">
<Trans i18nKey="continueAs" defaults="Continue as" />
</h1>
<div className="flex flex-col items-center gap-4">
<OptimizedAvatarImage
src={data?.image ?? undefined}
name={data?.name ?? ""}
size="xl"
/>
<div>
<div className="mb-1 h-6 font-medium">
{data?.name ?? <Skeleton className="inline-block h-5 w-16" />}
</div>
<div className="text-muted-foreground h-5 truncate text-sm">
{data?.email ?? <Skeleton className="inline-block h-full w-20" />}
</div>
</div>
</div>
<div>
<Button
size="lg"
loading={magicLinkFetch.isLoading}
onClick={async () => {
await magicLinkFetch.mutateAsync();
}}
variant="primary"
className="mt-6 w-full"
className="w-full"
>
<Trans i18nKey="continue" />
<Trans i18nKey="login" defaults="Login" />
</Button>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { z } from "zod";

import { getTranslation } from "@/i18n/server";

import { LoginPage } from "./login-page";
import { LoginPage } from "./components/login-page";

export const dynamic = "force-dynamic";

Expand Down
29 changes: 29 additions & 0 deletions apps/web/src/app/[locale]/(auth)/components/auth-page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
export function AuthPageContainer({ children }: { children: React.ReactNode }) {
return <div className="space-y-8 lg:space-y-10">{children}</div>;
}

export function AuthPageHeader({ children }: { children: React.ReactNode }) {
return <div className="space-y-1 text-center">{children}</div>;
}

export function AuthPageTitle({ children }: { children: React.ReactNode }) {
return <h1 className="text-2xl font-bold">{children}</h1>;
}

export function AuthPageDescription({
children,
}: {
children: React.ReactNode;
}) {
return <p className="text-muted-foreground">{children}</p>;
}

export function AuthPageContent({ children }: { children: React.ReactNode }) {
return <div className="space-y-4">{children}</div>;
}

export function AuthPageExternal({ children }: { children: React.ReactNode }) {
return (
<p className="text-muted-foreground px-4 py-3 text-center">{children}</p>
);
}
47 changes: 47 additions & 0 deletions apps/web/src/app/[locale]/(auth)/components/full-page-card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
export function FullPageCardContainer({
children,
}: {
children: React.ReactNode;
}) {
return (
<div className="flex h-screen flex-col gap-6 bg-gray-50 p-4">
<div className="rounded-xl border bg-white p-4">{children}</div>
</div>
);
}

export function FullPageCardHeader({
children,
}: {
children: React.ReactNode;
}) {
return <header>{children}</header>;
}

export function FullPageCardTitle({ children }: { children: React.ReactNode }) {
return <h1>{children}</h1>;
}

export function FullPageCardDescription({
children,
}: {
children: React.ReactNode;
}) {
return <p>{children}</p>;
}

export function FullPageCardContent({
children,
}: {
children: React.ReactNode;
}) {
return <main className="flex-1">{children}</main>;
}

export function FullPageCardFooter({
children,
}: {
children: React.ReactNode;
}) {
return <footer>{children}</footer>;
}
5 changes: 5 additions & 0 deletions apps/web/src/app/[locale]/(auth)/components/version-badge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { Badge } from "@rallly/ui/badge";

export function VersionBadge() {
return <Badge>v{process.env.NEXT_PUBLIC_APP_VERSION}</Badge>;
}
62 changes: 59 additions & 3 deletions apps/web/src/app/[locale]/(auth)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,63 @@
export default function Layout({ children }: { children: React.ReactNode }) {
import { cn } from "@rallly/ui";
import { DotPattern } from "@rallly/ui/dot-pattern";
import type { Metadata } from "next";
import { redirect, RedirectType } from "next/navigation";

import { getServerSession } from "@/auth";
import { Logo } from "@/components/logo";
import { isQuickCreateEnabled } from "@/features/quick-create";
import { QuickStartButton } from "@/features/quick-create/quick-create-button";
import { QuickStartWidget } from "@/features/quick-create/quick-create-widget";

export default async function Layout({
children,
}: {
children: React.ReactNode;
}) {
const session = await getServerSession();

if (session?.user.email) {
return redirect("/", RedirectType.replace);
}

return (
<div className="h-full p-3 sm:p-8">
<div className="mx-auto max-w-lg">{children}</div>
<div className="relative flex h-screen flex-col items-center justify-center bg-gray-100 p-2 lg:p-4">
<div className="z-10 flex w-full max-w-7xl flex-1 rounded-xl border bg-white shadow-sm lg:max-h-[720px] lg:p-2">
<div className="flex flex-1 flex-col gap-6 p-6 lg:p-16">
<div className="p-4">
<Logo className="mx-auto" />
</div>
<div className="flex h-full w-full flex-1 flex-col items-center justify-center">
<div className="w-full max-w-sm">{children}</div>
</div>
{isQuickCreateEnabled ? (
<div className="flex justify-center lg:hidden">
<QuickStartButton />
</div>
) : null}
</div>
{isQuickCreateEnabled ? (
<div className="relative hidden flex-1 flex-col justify-center rounded-lg border border-gray-100 bg-gray-50 lg:flex lg:p-16">
<div className="z-10 mx-auto w-full max-w-md">
<QuickStartWidget />
</div>
<DotPattern
cx={10}
cy={10}
className={cn(
"[mask-image:radial-gradient(400px_circle_at_top,white,transparent)]",
)}
/>
</div>
) : null}
</div>
</div>
);
}

export const metadata: Metadata = {
title: {
template: "%s - Rallly",
default: "Rallly",
},
};
16 changes: 16 additions & 0 deletions apps/web/src/app/[locale]/(auth)/login/actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"use server";

import { prisma } from "@rallly/database";
import { cookies } from "next/headers";

export async function setVerificationEmail(email: string) {
const count = await prisma.user.count({
where: {
email,
},
});

cookies().set("verification-email", email);

return count > 0;
}
21 changes: 21 additions & 0 deletions apps/web/src/app/[locale]/(auth)/login/components/auth-errors.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"use client";
import { useSearchParams } from "next/navigation";
import { useTranslation } from "react-i18next";

export function AuthErrors() {
const { t } = useTranslation();
const searchParams = useSearchParams();
const error = searchParams?.get("error");
if (error === "OAuthAccountNotLinked") {
return (
<p className="text-destructive text-sm">
{t("accountNotLinkedDescription", {
defaultValue:
"A user with this email already exists. Please log in using the original method.",
})}
</p>
);
}

return null;
}
Loading

0 comments on commit dbfbfae

Please sign in to comment.