Skip to content

Commit

Permalink
feat: ✨ adding sign in feature for new users
Browse files Browse the repository at this point in the history
  • Loading branch information
WasiqB committed Jan 5, 2025
1 parent fd8cc6b commit dcb148a
Show file tree
Hide file tree
Showing 18 changed files with 461 additions and 67 deletions.
9 changes: 9 additions & 0 deletions apps/web/app/(app)/dashboard/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
'use client';

export default function DashboardPage() {
return (
<div className='container mx-auto py-8'>
<h1 className='text-3xl font-bold'>Dashboard</h1>
</div>
);
}
14 changes: 14 additions & 0 deletions apps/web/app/(auth)/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { NavBar } from '@ultra-reporter/ui/home/nav-bar';

export default function AuthLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<>
<NavBar hideAuth={true} />
{children}
</>
);
}
97 changes: 97 additions & 0 deletions apps/web/app/(auth)/login/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
'use client';

import { Button } from '@ultra-reporter/ui/components/button';
import { DemoCarousel } from '@ultra-reporter/ui/components/demo-carousel';
import { Icons } from '@ultra-reporter/ui/components/icons';
import { useState } from 'react';

export default function AuthPage() {
const [isLoading, setIsLoading] = useState(false);

const handleAuth = async () => {
setIsLoading(true);
try {
const response = await fetch('/api/auth/login', {
method: 'POST',
});

if (!response.ok) {
throw new Error('Authentication failed');
}

const data = await response.json();

if (data.url) {
window.location.href = data.url;
} else {
throw new Error('No OAuth URL received');
}
} catch (error) {
console.error('Authentication error:', error);
// You might want to show an error message to the user here
} finally {
setIsLoading(false);
}
};

return (
<div className='container mx-auto flex min-h-screen items-center justify-center'>
<div className='grid w-full items-center gap-8 lg:grid-cols-2'>
{/* Demo Carousel Section */}
<div className='relative hidden h-[600px] lg:block'>
<DemoCarousel />
</div>

{/* Auth Section */}
<div className='mx-auto w-full max-w-md space-y-8'>
<div className='space-y-2 text-center'>
<h1 className='text-3xl font-bold tracking-tight'>
Welcome to Ultra Reporter
</h1>
<p className='text-muted-foreground text-lg'>
Sign in to your account or create a new one
</p>
</div>

<div className='space-y-4'>
<Button
variant='default'
size='lg'
className='w-full py-6 text-lg'
onClick={handleAuth}
disabled={isLoading}
>
{isLoading && (
<Icons.spinner className='mr-2 h-5 w-5 animate-spin' />
)}
<Icons.google className='mr-2 h-5 w-5' />
Continue with Google
</Button>

<div className='relative'>
<div className='absolute inset-0 flex items-center'>
<span className='w-full border-t' />
</div>
<div className='relative flex justify-center text-sm uppercase'>
<span className='bg-background text-muted-foreground px-2'>
Secure Authentication
</span>
</div>
</div>

<p className='text-muted-foreground text-center text-sm'>
By continuing, you agree to our{' '}
<a href='/terms' className='hover:text-primary underline'>
Terms of Service
</a>{' '}
and{' '}
<a href='/privacy' className='hover:text-primary underline'>
Privacy Policy
</a>
</p>
</div>
</div>
</div>
</div>
);
}
48 changes: 48 additions & 0 deletions apps/web/app/api/auth/login/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { logger } from '@ultra-reporter/logger';
import { createClient } from '@ultra-reporter/supabase/server';
import { NextResponse } from 'next/server';

export async function POST(req: Request) {
try {
const supabase = await createClient();
const origin = req.headers.get('origin') || 'http://localhost:3000';

// Get the URL for Google OAuth sign-in
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'google',
options: {
redirectTo: `${origin}/auth/callback`,
queryParams: {
access_type: 'offline',
prompt: 'consent',
},
scopes: 'email profile',
},
});

if (error) {
logger.error('OAuth initialization failed', { error });
return NextResponse.json(
{ error: 'Failed to start OAuth flow' },
{ status: 500 }
);
}

if (!data.url) {
logger.error('No OAuth URL returned');
return NextResponse.json(
{ error: 'Invalid OAuth configuration' },
{ status: 500 }
);
}

logger.info('OAuth flow initiated', { url: data.url });
return NextResponse.json({ url: data.url }, { status: 200 });
} catch (error) {
logger.error('Unexpected error during OAuth initialization', { error });
return NextResponse.json(
{ error: 'Internal server error' },
{ status: 500 }
);
}
}
40 changes: 0 additions & 40 deletions apps/web/app/api/auth/sign-up/route.ts

This file was deleted.

20 changes: 20 additions & 0 deletions apps/web/middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { updateSession } from '@ultra-reporter/supabase/middleware';
import { type NextRequest } from 'next/server';

export async function middleware(request: NextRequest) {
return await updateSession(request);
}

export const config = {
matcher: [
/*
* Match all request paths except:
* - _next/static (static files)
* - _next/image (image optimization files)
* - favicon.ico (favicon file)
* - images - .svg, .png, .jpg, .jpeg, .gif, .webp
* Feel free to modify this pattern to include more paths.
*/
'/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)',
],
};
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"@release-it-plugins/lerna-changelog": "^7.0.0",
"@stylistic/eslint-plugin-js": "^2.12.1",
"@stylistic/eslint-plugin-ts": "^2.12.1",
"@types/node": "^22.10.4",
"@types/node": "^22.10.5",
"@typescript-eslint/eslint-plugin": "^8.19.0",
"@typescript-eslint/parser": "^8.19.0",
"@vercel/style-guide": "^6.0.0",
Expand Down
8 changes: 4 additions & 4 deletions packages/supabase/src/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ export const updateSession = async (request: NextRequest) => {

const user = await supabase.auth.getUser();

if (request.nextUrl.pathname.startsWith('/protected') && user.error) {
return NextResponse.redirect(new URL('/sign-in', request.url));
if (request.nextUrl.pathname.startsWith('/dashboard') && user.error) {
return NextResponse.redirect(new URL('/login', request.url));
}

if (request.nextUrl.pathname === '/' && !user.error) {
return NextResponse.redirect(new URL('/protected', request.url));
if (request.nextUrl.pathname === '/login' && !user.error) {
return NextResponse.redirect(new URL('/dashboard', request.url));
}

return response;
Expand Down
5 changes: 4 additions & 1 deletion packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"@radix-ui/react-separator": "^1.1.1",
"@radix-ui/react-slot": "^1.1.1",
"@radix-ui/react-switch": "^1.1.2",
"@radix-ui/react-tabs": "^1.1.2",
"@radix-ui/react-toast": "^1.2.4",
"@radix-ui/react-tooltip": "^1.1.6",
"@tanstack/react-table": "^8.20.6",
Expand All @@ -54,11 +55,13 @@
"react-hook-form": "^7.54.2",
"recharts": "^2.15.0",
"tailwindcss-animate": "^1.0.7",
"zod": "^3.24.1"
"zod": "^3.24.1",
"zxcvbn": "^4.4.2"
},
"devDependencies": {
"@types/react": "^19.0.2",
"@types/react-dom": "^19.0.2",
"@types/zxcvbn": "^4.4.5",
"@ultra-reporter/feature-toggle": "workspace:*",
"@ultra-reporter/typescript-config": "workspace:*",
"@ultra-reporter/utils": "workspace:*",
Expand Down
3 changes: 1 addition & 2 deletions packages/ui/src/components/button.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { Slot } from '@radix-ui/react-slot';
import { cn } from '@ultra-reporter/utils/cn';
import { cva, type VariantProps } from 'class-variance-authority';
import * as React from 'react';

import { cn } from '@ultra-reporter/utils/cn';

const buttonVariants = cva(
'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
{
Expand Down
15 changes: 7 additions & 8 deletions packages/ui/src/components/card.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as React from 'react';

import { cn } from '@ultra-reporter/utils/cn';
import * as React from 'react';

const Card = React.forwardRef<
HTMLDivElement,
Expand Down Expand Up @@ -30,10 +29,10 @@ const CardHeader = React.forwardRef<
CardHeader.displayName = 'CardHeader';

const CardTitle = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLHeadingElement>
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<h3
<div
ref={ref}
className={cn('font-semibold leading-none tracking-tight', className)}
{...props}
Expand All @@ -42,10 +41,10 @@ const CardTitle = React.forwardRef<
CardTitle.displayName = 'CardTitle';

const CardDescription = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<p
<div
ref={ref}
className={cn('text-muted-foreground text-sm', className)}
{...props}
Expand Down
Loading

0 comments on commit dcb148a

Please sign in to comment.