Skip to content

Commit

Permalink
feat(auth): login added
Browse files Browse the repository at this point in the history
  • Loading branch information
imbhargav5 committed Sep 21, 2023
1 parent c250edc commit 6ca6940
Show file tree
Hide file tree
Showing 91 changed files with 3,415 additions and 224 deletions.
16 changes: 16 additions & 0 deletions components.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "default",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "tailwind.config.js",
"css": "src/app/globals.css",
"baseColor": "slate",
"cssVariables": false
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils"
}
}
1 change: 0 additions & 1 deletion next.config.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
export default {
experimental: {
appDir: true,
serverActions: true,
},
images: {
Expand Down
21 changes: 14 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,34 +24,41 @@
"@commitlint/config-conventional": "^17.4.4",
"@headlessui/react": "^1.7.11",
"@heroicons/react": "^2.0.16",
"@hookform/resolvers": "^3.3.1",
"@radix-ui/react-context-menu": "^2.1.3",
"@radix-ui/react-dialog": "^1.0.2",
"@radix-ui/react-dropdown-menu": "^2.0.2",
"@radix-ui/react-hover-card": "^1.0.5",
"@radix-ui/react-label": "^2.0.0",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-navigation-menu": "^1.1.1",
"@radix-ui/react-popover": "^1.0.5",
"@radix-ui/react-select": "^1.2.0",
"@radix-ui/react-slider": "^1.1.1",
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-switch": "^1.0.2",
"@supabase/auth-helpers-nextjs": "^0.7.3",
"@supabase/auth-helpers-nextjs": "^0.8.1",
"@supabase/auth-helpers-react": "^0.3.1",
"@supabase/supabase-js": "^2.31.0",
"@tailwindcss/typography": "^0.5.9",
"@tanstack/react-query": "^4.24.10",
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
"lucide-react": "0.206.0",
"next": "^13.4.19",
"lucide-react": "^0.279.0",
"next": "^13.5.1",
"next-seo": "^5.15.0",
"next-sitemap": "^3.1.52",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hot-toast": "^2.4.0",
"react-hook-form": "^7.46.2",
"react-hot-toast": "^2.4.1",
"react-no-ssr": "^1.1.0",
"rooks": "^7.14.1",
"sonner": "^1.0.3",
"tailwind-merge": "^1.14.0",
"tailwindcss": "^3.2.7",
"tailwindcss-animate": "^1.0.6",
"url-join": "^5.0.0"
"tailwindcss-animate": "^1.0.7",
"url-join": "^5.0.0",
"zod": "^3.22.2"
},
"devDependencies": {
"@commitlint/cli": "^17.4.4",
Expand Down
Binary file added public/assets/admin-image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/help-assets/organisations-teams.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/help-assets/teams-projects.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/image-background-login.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/login-asset-dashboard.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/logo-login.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/onboardingFeatures/adminPanel.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/onboardingFeatures/layout.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/user-image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/logos/logo-black.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/logos/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/logos/nextbase copy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/logos/nextbase-dark-logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/logos/nextbase-light-logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/logos/nextbase@2x copy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/logos/nextbase@3x copy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
186 changes: 186 additions & 0 deletions public/logos/nextbase_navlogo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
185 changes: 185 additions & 0 deletions public/logos/nextbase_navlogo_small.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
62 changes: 62 additions & 0 deletions src/app/(dynamic-pages)/(login-pages)/ClientLayout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
'use client';

import { ReactNode, useEffect } from 'react';
import Image from 'next/image';
import { useRouter } from 'next/navigation';
import { T } from '@/components/ui/Typography';

export function ClientLayout({ children }: { children: ReactNode }) {
const router = useRouter();
useEffect(() => {
router.prefetch('/dashboard');
}, []);
return (
<div className=" h-full dark:bg-gray-900/20">
<div
className="grid"
style={{
gridTemplateColumns: '1fr 1fr',
}}
>
<div className="text-center flex flex-col items-center justify-center space-y-8 h-screen">
<div>{children}</div>
</div>
<div className="relative p-3">
{/* Background Overlay */}

{/* Blue Background Image */}
<div
className="gap-10 bg-cover flex flex-col justify-between rounded-xl w-full dark:bg-gray-800 bg-gray-100 bg-opacity-90 h-full px-10 pt-10 pb-10"
// style={{ backgroundImage: `url(${LoginBackgroundLight.src})` }}
>
<div className="ml-6 space-y-8">
<div>
<Image
width="600"
src={'/assets/login-asset-dashboard.png'}
height="450"
alt="Login Header"
/>
</div>

<div className=" w-[640px]">
<T.H3 className=" tracking-tight">
<p className="text-6xl -ml-4 mb-0 leading-none">οΌ‚</p>
We are now able to ship our product quicker, allowing us to
focus on building the features that matter most to our
customers and not worry about the infrastructure.
</T.H3>
<div className="mt-8 flex justify-between">
<T.P>⭐️ ⭐️ ⭐️ ⭐️ ⭐️</T.P>
<T.P className="dark:text-gray-100 text-base font-[500]">
Jonathan Smith - CEO of Company
</T.P>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Typography as T } from 'src/components/ui/Typography';

export default function AuthErrorPage() {
return (
<div>
<T.H1>Authentication Error</T.H1>
<T.P>An error occurred during authentication. Please try again.</T.P>
</div>
);
}
29 changes: 29 additions & 0 deletions src/app/(dynamic-pages)/(login-pages)/auth/callback/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs';
import { revalidatePath } from 'next/cache';
import { cookies } from 'next/headers';
import { NextResponse } from 'next/server';

export async function GET(request: Request) {
const requestUrl = new URL(request.url);
const code = requestUrl.searchParams.get('code');

if (code) {
const supabase = createRouteHandlerClient({ cookies });
try {
// Exchange the code for a session
await supabase.auth.exchangeCodeForSession(code);
} catch (error) {
// Handle error
console.error('Failed to exchange code for session: ', error);
// Potentially return an error response here
}
}

// Revalidates the path in Next.js cache
revalidatePath('/');

// Constructs the URL to redirect to after the sign in process completes
const redirectTo = new URL('/', requestUrl.origin);

return NextResponse.redirect(redirectTo);
}
21 changes: 21 additions & 0 deletions src/app/(dynamic-pages)/(login-pages)/auth/confirm/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs';
import { cookies } from 'next/headers';
import { NextRequest, NextResponse } from 'next/server';

export async function GET(req: NextRequest) {
const { searchParams } = new URL(req.url);
const token_hash = searchParams.get('token_hash');
const next = searchParams.get('next') ?? '/';
if (token_hash) {
const supabase = createRouteHandlerClient({ cookies });
const { error } = await supabase.auth.verifyOtp({
type: 'magiclink',
token_hash,
});
if (!error) {
return NextResponse.redirect(new URL(`/${next.slice(1)}`, req.url));
}
}
// return the user to an error page with some instructions
return NextResponse.redirect(new URL('/auth/auth-code-error', req.url));
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
'use client';
import { Email } from '@/components/Auth/Email';
import { T } from '@/components/ui/Typography';
import { useResetPassword } from '@/utils/react-query-hooks';
import { useState } from 'react';

export function ForgotPassword() {
const [successMessage, setSuccessMessage] = useState<string | null>(null);
const magicLinkMutation = useResetPassword({
onSuccess: () => {
setSuccessMessage('A magic link has been sent to your email!');
},
});

return (
<div className="container h-full grid items-center text-left max-w-lg mx-auto overflow-auto">
<div className="space-y-8 ">
{/* <Auth providers={['twitter']} supabaseClient={supabase} /> */}
<div className="flex flex-col items-start gap-0 w-[320px]">
<T.H4>Forgot Password</T.H4>
<T.P className="text-muted-foreground">
Enter your email to recieve a Magic Link to reset your password.
</T.P>
</div>

<Email
onSubmit={(email) => {
magicLinkMutation.mutate({
email,
});
}}
successMessage={successMessage}
isLoading={magicLinkMutation.isLoading}
view="forgot-password"
/>
</div>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { ForgotPassword } from './ForgotPassword';

export default function ForgotPasswordPage() {
return <ForgotPassword />;
}
44 changes: 44 additions & 0 deletions src/app/(dynamic-pages)/(login-pages)/init-auth/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
'use client';
import { T } from '@/components/ui/Typography';
import { useSession } from '@supabase/auth-helpers-react';
import { useRouter } from 'next/navigation';
import { useState } from 'react';
import { useDidMount } from 'rooks';

export default function HomePage() {
const session = useSession();
const router = useRouter();
const [loadingState, setLoadingState] = useState<
'loading' | 'logged-in' | 'logged-out'
>('loading');

// Intentionally not using useEffect here because we want to run this
// code only once, on mount and not interrupt auth flow.
useDidMount(() => {
if (session?.user) {
setLoadingState('logged-in');
router.push('/dashboard');
} else {
setLoadingState('logged-out');
router.push('/login');
}
});

let content = <span>Please wait...</span>;
if (loadingState === 'logged-in') {
content = <span>Redirecting to dashboard...</span>;
} else if (loadingState === 'logged-out') {
content = (
<div className="space-y-4">
<T.P>Not logged in</T.P>
<span>Redirecting to login...</span>
</div>
);
}

return (
<div className="w-full h-full flex items-center justify-center">
{content}
</div>
);
}
9 changes: 9 additions & 0 deletions src/app/(dynamic-pages)/(login-pages)/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { ClientLayout } from './ClientLayout';

export default function AuthLayout({
children,
}: {
children: React.ReactNode;
}) {
return <ClientLayout>{children}</ClientLayout>;
}
72 changes: 72 additions & 0 deletions src/app/(dynamic-pages)/(login-pages)/login/Login.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
'use client';
import { RenderProviders } from '@/components/Auth/RenderProviders';
import { Email } from '@/components/Auth/Email';
import { EmailAndPassword } from '@/components/Auth/EmailAndPassword';
import {
useSignInWithMagicLink,
useSignInWithPassword,
useSignInWithProvider,
} from '@/utils/react-query-hooks';
import { useState } from 'react';
import { useRouter } from 'next/navigation';
import { T } from '@/components/ui/Typography';

export function Login() {
const router = useRouter();

function redirectToDashboard() {
router.refresh();
router.push('/auth/callback');
}
const [successMessage, setSuccessMessage] = useState<string | null>(null);
const magicLinkMutation = useSignInWithMagicLink({
onSuccess: () => {
setSuccessMessage('A magic link has been sent to your email!');
},
});
const passwordMutation = useSignInWithPassword({
onSuccess: redirectToDashboard,
});
const providerMutation = useSignInWithProvider();
return (
<div className="container h-full grid items-center text-left max-w-lg mx-auto overflow-auto">
<div className="space-y-8 ">
{/* <Auth providers={['twitter']} supabaseClient={supabase} /> */}
<div className="flex flex-col items-start gap-0 w-[320px]">
<T.H4 className="leading-7">Login to Nextbase</T.H4>
<T.P className="text-base text-left text-muted-foreground">
Login with the account you used to signup.
</T.P>
</div>
<RenderProviders
providers={['google', 'github', 'twitter']}
isLoading={providerMutation.isLoading}
onProviderLoginRequested={(provider) => {
providerMutation.mutate({
provider,
});
}}
/>
<hr />
<Email
onSubmit={(email) => {
magicLinkMutation.mutate({
email,
});
}}
successMessage={successMessage}
isLoading={magicLinkMutation.isLoading}
view="sign-in"
/>
<hr />
<EmailAndPassword
isLoading={passwordMutation.isLoading}
onSubmit={(data) => {
passwordMutation.mutate(data);
}}
view="sign-in"
/>
</div>
</div>
);
}
5 changes: 5 additions & 0 deletions src/app/(dynamic-pages)/(login-pages)/login/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { Login } from './Login';

export default function LoginPage() {
return <Login />;
}
Loading

0 comments on commit 6ca6940

Please sign in to comment.