mirror of
https://github.com/penxio/penx.git
synced 2026-04-19 03:03:06 -04:00
feat: create login page
This commit is contained in:
44
apps/web/src/components/LoginWithGoogleButton.tsx
Normal file
44
apps/web/src/components/LoginWithGoogleButton.tsx
Normal file
@@ -0,0 +1,44 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Box } from '@fower/react'
|
||||
import { signIn } from 'next-auth/react'
|
||||
import { useSearchParams } from 'next/navigation'
|
||||
import { toast } from 'sonner'
|
||||
import { Button, Spinner } from 'uikit'
|
||||
import { IconGoogle } from '@penx/icons'
|
||||
|
||||
export default function LoginWithGoogleButton() {
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
// Get error message added by next/auth in URL.
|
||||
const searchParams = useSearchParams()
|
||||
const error = searchParams?.get('error')
|
||||
|
||||
useEffect(() => {
|
||||
const errorMessage = Array.isArray(error) ? error.pop() : error
|
||||
errorMessage && toast.error(errorMessage)
|
||||
}, [error])
|
||||
|
||||
return (
|
||||
<Button
|
||||
disabled={loading}
|
||||
size="lg"
|
||||
colorScheme="white"
|
||||
onClick={() => {
|
||||
setLoading(true)
|
||||
signIn('google', { callbackUrl: `/editor` })
|
||||
}}
|
||||
cursorNotAllowed={loading}
|
||||
gapX2
|
||||
w-240
|
||||
>
|
||||
{loading ? (
|
||||
<Spinner />
|
||||
) : (
|
||||
<>
|
||||
<IconGoogle />
|
||||
<Box>Login with Google</Box>
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
import { PrismaAdapter } from '@next-auth/prisma-adapter'
|
||||
import NextAuth from 'next-auth'
|
||||
import { JWT } from 'next-auth/jwt'
|
||||
import jwt from 'jsonwebtoken'
|
||||
import NextAuth, { NextAuthOptions } from 'next-auth'
|
||||
import { encode, JWT } from 'next-auth/jwt'
|
||||
import GoogleProvider from 'next-auth/providers/google'
|
||||
import { prisma } from '@penx/db'
|
||||
|
||||
export default NextAuth({
|
||||
export const authOptions: NextAuthOptions = {
|
||||
// Configure one or more authentication providers
|
||||
providers: [
|
||||
GoogleProvider({
|
||||
@@ -23,14 +24,32 @@ export default NextAuth({
|
||||
|
||||
adapter: PrismaAdapter(prisma),
|
||||
pages: {
|
||||
signIn: `/`,
|
||||
verifyRequest: `/`,
|
||||
error: '/', // Error code passed in query string as ?error=
|
||||
signIn: `/login`,
|
||||
verifyRequest: `/login`,
|
||||
error: '/login', // Error code passed in query string as ?error=
|
||||
},
|
||||
// jwt: {
|
||||
// maxAge: 30 * 24 * 30 * 60,
|
||||
// decode: async ({ token, secret }) => {
|
||||
// console.log('============dencode token', token, 'secret', secret)
|
||||
// const result = jwt.verify(token!, secret)
|
||||
// console.log('========result:', result)
|
||||
|
||||
// return result
|
||||
// },
|
||||
|
||||
// encode: async ({ token, secret }) => {
|
||||
// console.log('encode token', token, 'secret', secret)
|
||||
// const encoded = jwt.sign(token!, secret, { algorithm: 'HS256' })
|
||||
// console.log('========encoded:', encoded)
|
||||
|
||||
// return encoded
|
||||
// },
|
||||
// },
|
||||
|
||||
callbacks: {
|
||||
async signIn({ user, account, profile }) {
|
||||
console.log('user, account:', user, 'account:', account)
|
||||
// console.log('============user:', user, 'account:', account)
|
||||
// await initSpace(user.id, user.name!)
|
||||
return true
|
||||
},
|
||||
@@ -44,12 +63,15 @@ export default NextAuth({
|
||||
|
||||
if (account) {
|
||||
// Save the access token and refresh token in the JWT on the initial login
|
||||
return {
|
||||
const jwt: JWT = {
|
||||
...token,
|
||||
accessToken: account.access_token,
|
||||
accessToken: account.access_token!,
|
||||
expiresAt: Math.floor(Date.now() / 1000 + account.expires_at!),
|
||||
refreshToken: account.refresh_token,
|
||||
} as JWT
|
||||
refreshToken: account.refresh_token!,
|
||||
}
|
||||
// console.log('==============jwt:', jwt)
|
||||
|
||||
return jwt
|
||||
}
|
||||
return token
|
||||
},
|
||||
@@ -58,7 +80,12 @@ export default NextAuth({
|
||||
session.accessToken = token.accessToken as string
|
||||
session.userId = token.uid as string
|
||||
;(session.user as any).id = token.uid
|
||||
|
||||
// console.log('session:', session, 'token:', token)
|
||||
|
||||
return session
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export default NextAuth(authOptions)
|
||||
|
||||
62
apps/web/src/pages/login.tsx
Normal file
62
apps/web/src/pages/login.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
import { Suspense } from 'react'
|
||||
import { Box } from '@fower/react'
|
||||
import { GetServerSideProps } from 'next'
|
||||
import { getServerSession } from 'next-auth'
|
||||
import LoginWithGoogleButton from '~/components/LoginWithGoogleButton'
|
||||
import { Logo } from '~/components/Logo'
|
||||
import { authOptions } from './api/auth/[...nextauth]'
|
||||
|
||||
export default function LoginPage() {
|
||||
return (
|
||||
<Box column h-100vh>
|
||||
<Box mx-auto py8 toCenter>
|
||||
<Logo to="/" />
|
||||
</Box>
|
||||
<Box column flex-1 toCenter>
|
||||
<Box
|
||||
toCenter
|
||||
py10
|
||||
roundedXL
|
||||
mx-auto
|
||||
bgWhite
|
||||
column
|
||||
mt--200
|
||||
w={['100%', '100%', 480]}
|
||||
>
|
||||
<Box as="h1" fontBold>
|
||||
Welcome to PenX
|
||||
</Box>
|
||||
<Box as="p" textCenter mb6 leadingNormal px10 gray500>
|
||||
PenX is an open-source collaborative editor to manage Markdown
|
||||
content
|
||||
</Box>
|
||||
<Box column gap4>
|
||||
<Suspense fallback={<Box my2 h10 w-100p border borderStone200 />}>
|
||||
<LoginWithGoogleButton />
|
||||
</Suspense>
|
||||
</Box>
|
||||
{/* <Box pt6>
|
||||
You can also <Box as="a"> continue with SAML SSO</Box>
|
||||
</Box> */}
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
export const getServerSideProps: GetServerSideProps = async function (context) {
|
||||
const session = await getServerSession(context.req, context.res, authOptions)
|
||||
|
||||
if (session) {
|
||||
return {
|
||||
redirect: {
|
||||
destination: '/editor',
|
||||
permanent: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
props: {},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user