Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sign in and sign up custom pages #92

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions apps/web/app/api/auth/signin/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
'use client'

import { signIn } from 'next-auth/react'
import { useState } from 'react'
import { useSearchParams } from 'next/navigation'

export default function SignIn() {
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [error, setError] = useState('')
const searchParams = useSearchParams()

const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
setError('')

const result = await signIn('credentials', {
username: email,
password: password,
redirect: false,
})

if (result?.error) {
setError('Invalid email or password')
} else {
window.location.href = searchParams.get('callbackUrl') || '/'
}
}

const handleGitHubSignIn = () => {
signIn('github', { callbackUrl: searchParams.get('callbackUrl') || '/' })
}

return (
<div className="flex flex-col items-center justify-center grow">
<div className="w-full md:w-1/4 p-4 flex flex-col items-center justify-center">
<div className="flex flex-col items-center justify-center gap-2 mb-2">
<img src="/SmallA2.svg" alt="logo" className="w-[40px]" />
<div className="text-2xl font-bold">Sign in to your account</div>
<div className="text-sm mx-2 text-center text-gray-500">Sign in to start your coding journey and compete in challenges.</div>
</div>
<div className="w-full flex flex-col items-center justify-center gap-2">
<div className="w-full flex items-center gap-[1px] border-[0.5px] border-gray-300 rounded-md p-2">
<img src="/email.svg" alt="email" className="w-[17px] h-[16px] m-2" />
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="[email protected]"
className="w-full bg-transparent focus:outline-none rounded-md"
required
/>
</div>
<div className="w-full flex items-center justify-center gap-[1px] border-[0.5px] border-gray-300 rounded-md p-2">
<img src="/lock.svg" alt="lock" className="w-[17px] h-[16px] m-2" />
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Password"
className="w-full bg-transparent focus:outline-none"
required
/>
</div>
{error && <p className="text-red-500 m-2">{error}</p>}
<button onClick={handleSubmit} type="submit" className="bg-blue-500 text-white p-2 rounded-md w-full">Sign In</button>
<div className="flex items-center justify-center w-full my-2">
<div className="border-t border-gray-300 flex-grow"></div>
<span className="px-4 text-gray-500">or</span>
<div className="border-t border-gray-300 flex-grow"></div>
</div>
<button
onClick={handleGitHubSignIn}
type="button"
className="bg-gray-800 text-white p-2 rounded-md w-full flex items-center justify-center gap-2"
>
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" aria-hidden="true">
<path fillRule="evenodd" d="M10 0C4.477 0 0 4.484 0 10.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0110 4.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.203 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.942.359.31.678.921.678 1.856 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0020 10.017C20 4.484 15.522 0 10 0z" clipRule="evenodd" />
</svg>
Login with GitHub
</button>
</div>
</div>
</div>
)
}
86 changes: 86 additions & 0 deletions apps/web/app/api/auth/signup/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
'use client'

import { signIn } from 'next-auth/react'
import { useState } from 'react'
import { useSearchParams } from 'next/navigation'

export default function SignUp() {
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [error, setError] = useState('')
const searchParams = useSearchParams()

const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
setError('')

const result = await signIn('credentials', {
username: email,
password: password,
redirect: false,
})

if (result?.error) {
setError('Sign up failed. Please try again.')
} else {
window.location.href = searchParams.get('callbackUrl') || '/'
}
}

const handleGitHubSignUp = () => {
signIn('github', { callbackUrl: searchParams.get('callbackUrl') || '/' })
}

return (
<div className="flex flex-col items-center justify-center grow">
<div className="w-full md:w-1/4 p-4 flex flex-col items-center justify-center">
<div className="flex flex-col items-center justify-center gap-2 mb-2">
<img src="/SmallA2.svg" alt="logo" className="w-[40px]" />
<div className="text-2xl font-bold">Create an account</div>
<div className="text-sm mx-2 text-center text-gray-500">Sign up to start your coding journey and compete in challenges.</div>
</div>
<div className="w-full flex flex-col items-center justify-center gap-2">
<div className="w-full flex items-center gap-[1px] border-[0.5px] border-gray-300 rounded-md p-2">
<img src="/email.svg" alt="email" className="w-[17px] h-[16px] m-2" />
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="[email protected]"
className="w-full bg-transparent focus:outline-none rounded-md"
required
/>
</div>
<div className="w-full flex items-center justify-center gap-[1px] border-[0.5px] border-gray-300 rounded-md p-2">
<img src="/lock.svg" alt="lock" className="w-[17px] h-[16px] m-2" />
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Password"
className="w-full bg-transparent focus:outline-none"
required
/>
</div>
{error && <p className="text-red-500 m-2">{error}</p>}
<button onClick={handleSubmit} type="submit" className="bg-blue-500 text-white p-2 rounded-md w-full">Sign Up</button>
<div className="flex items-center justify-center w-full my-2">
<div className="border-t border-gray-300 flex-grow"></div>
<span className="px-4 text-gray-500">or</span>
<div className="border-t border-gray-300 flex-grow"></div>
</div>
<button
onClick={handleGitHubSignUp}
type="button"
className="bg-gray-800 text-white p-2 rounded-md w-full flex items-center justify-center gap-2"
>
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" aria-hidden="true">
<path fillRule="evenodd" d="M10 0C4.477 0 0 4.484 0 10.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0110 4.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.203 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.942.359.31.678.921.678 1.856 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0020 10.017C20 4.484 15.522 0 10 0z" clipRule="evenodd" />
</svg>
Sign up with GitHub
</button>
</div>
</div>
</div>
)
}
4 changes: 3 additions & 1 deletion apps/web/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,13 @@ export default function RootLayout({
}): JSX.Element {
return (
<html lang="en">
<body className={chivo.variable + " " + rubik.variable}>
<body className={chivo.variable + " " + rubik.variable +" "+"min-h-dvh flex flex-col "}>
<ThemeProvider attribute="class" defaultTheme="system" enableSystem disableTransitionOnChange>
<Providers>
<Appbar />
{/* <div className=""> */}
{children}
{/* </div> */}
<Footer />
</Providers>
</ThemeProvider>
Expand Down
18 changes: 17 additions & 1 deletion apps/web/app/lib/auth.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { db } from "../db";
import CredentialsProvider from "next-auth/providers/credentials";
import GitHubProvider from "next-auth/providers/github";
import { PrismaAdapter } from "@auth/prisma-adapter";
import bcrypt from "bcrypt";
import { NextAuthOptions } from "next-auth";
import { JWT } from "next-auth/jwt";
import { JWTPayload, SignJWT, importJWK } from "jose";
import { Session } from "next-auth";

import { Adapter } from "next-auth/adapters";


interface token extends JWT {
uid: string;
jwtToken: string;
Expand Down Expand Up @@ -40,7 +45,8 @@ const generateJWT = async (payload: JWTPayload) => {
return jwt;
};

export const authOptions = {
export const authOptions: NextAuthOptions = {
adapter: PrismaAdapter(db) as Adapter,
providers: [
CredentialsProvider({
name: "Credentials",
Expand Down Expand Up @@ -116,6 +122,10 @@ export const authOptions = {
}
},
}),
GitHubProvider({
clientId: process.env.GITHUB_ID??'',
clientSecret: process.env.GITHUB_SECRET??''
})
],
secret: process.env.NEXTAUTH_SECRET || "secr3t",
callbacks: {
Expand All @@ -137,4 +147,10 @@ export const authOptions = {
return newToken;
},
},
pages: {
signIn: '/auth/signin',
// signUp: '/auth/signup',
newUser: '/auth/signup',
error: '/auth/error',
},
} satisfies NextAuthOptions;
24 changes: 24 additions & 0 deletions apps/web/public/SmallA2.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions apps/web/public/email.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions apps/web/public/lock.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
-- AlterTable
ALTER TABLE "User" ADD COLUMN "emailVerified" TIMESTAMP(3),
ADD COLUMN "image" TEXT;

-- CreateTable
CREATE TABLE "Account" (
"id" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"type" TEXT NOT NULL,
"provider" TEXT NOT NULL,
"providerAccountId" TEXT NOT NULL,
"refresh_token" TEXT,
"access_token" TEXT,
"expires_at" INTEGER,
"token_type" TEXT,
"scope" TEXT,
"id_token" TEXT,
"session_state" TEXT,

CONSTRAINT "Account_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "Session" (
"id" TEXT NOT NULL,
"sessionToken" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"expires" TIMESTAMP(3) NOT NULL,

CONSTRAINT "Session_pkey" PRIMARY KEY ("id")
);

-- CreateIndex
CREATE UNIQUE INDEX "Account_provider_providerAccountId_key" ON "Account"("provider", "providerAccountId");

-- CreateIndex
CREATE UNIQUE INDEX "Session_sessionToken_key" ON "Session"("sessionToken");

-- AddForeignKey
ALTER TABLE "Account" ADD CONSTRAINT "Account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "Session" ADD CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
36 changes: 34 additions & 2 deletions packages/db/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,51 @@ datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model Account {
id String @id @default(cuid())
userId String
type String
provider String
providerAccountId String
refresh_token String? @db.Text
access_token String? @db.Text
refresh_token_expires_in Int?
expires_at Int?
token_type String?
scope String?
id_token String? @db.Text
session_state String?

user User @relation(fields: [userId], references: [id], onDelete: Cascade)

@@unique([provider, providerAccountId])
}

model Session {
id String @id @default(cuid())
sessionToken String @unique
userId String
expires DateTime
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}


model User {
id String @id @default(cuid())
email String @unique
email String? @unique
name String?
token String?
password String
password String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
contestSubmissions ContestSubmission[]
role UserRole @default(USER)
submissions Submission[]
contestPoints ContestPoints[]
accounts Account[]
sessions Session[]
emailVerified DateTime?
image String?
}

model Contest {
Expand Down