mirror of
https://github.com/koreanbots/core.git
synced 2025-12-15 14:10:22 +00:00
chore: improved user login interaction
This commit is contained in:
parent
28665bd7a2
commit
21c803aa0d
@ -1,28 +1,42 @@
|
||||
/* eslint-disable jsx-a11y/click-events-have-key-events */
|
||||
/* eslint-disable jsx-a11y/no-noninteractive-tabindex */
|
||||
/* eslint-disable jsx-a11y/no-static-element-interactions */
|
||||
import { useState } from 'react'
|
||||
import { useEffect, useState } from 'react'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
import { redirectTo } from '@utils/Tools'
|
||||
import { UserCache } from '@types'
|
||||
import { User, UserCache } from '@types'
|
||||
|
||||
import DiscordAvatar from '@components/DiscordAvatar'
|
||||
import Fetch from '@utils/Fetch'
|
||||
|
||||
const Navbar = (): JSX.Element => {
|
||||
let userCache:UserCache
|
||||
try {
|
||||
userCache = JSON.parse(localStorage.userCache)
|
||||
} catch {
|
||||
userCache = null
|
||||
}
|
||||
|
||||
const Navbar = ({ token }:{ token: string }): JSX.Element => {
|
||||
const [userCache, setUserCache] = useState<UserCache>()
|
||||
const [navbarOpen, setNavbarOpen] = useState<boolean>(false)
|
||||
const [dropdownOpen, setDropdownOpen] = useState<boolean>(false)
|
||||
const router = useRouter()
|
||||
const logged = userCache?.id && userCache.version === 2
|
||||
const dev = router.pathname.startsWith('/developers')
|
||||
|
||||
useEffect(() => {
|
||||
try {
|
||||
if(localStorage.userCache) {
|
||||
setUserCache(token ? JSON.parse(localStorage.userCache) : null)
|
||||
}
|
||||
Fetch<User>('/users/@me').then(data => {
|
||||
if(data.code !== 200) return
|
||||
setUserCache(JSON.parse(localStorage.userCache = JSON.stringify({
|
||||
id: data.data.id,
|
||||
username: data.data.username,
|
||||
tag: data.data.tag,
|
||||
version: 2
|
||||
})))
|
||||
})
|
||||
} catch {
|
||||
setUserCache(null)
|
||||
}
|
||||
}, [ token ])
|
||||
return (
|
||||
<>
|
||||
<nav className='fixed z-40 top-0 flex flex-wrap items-center justify-between px-2 py-3 w-full text-gray-100 dark:bg-discord-black bg-discord-blurple bg-transparent lg:absolute'>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import Head from 'next/head'
|
||||
import type { AppProps } from 'next/app'
|
||||
import App, { AppContext, AppProps } from 'next/app'
|
||||
import dynamic from 'next/dynamic'
|
||||
import { Router, useRouter } from 'next/router'
|
||||
import { useEffect, useState } from 'react'
|
||||
@ -8,7 +8,7 @@ import NProgress from 'nprogress'
|
||||
|
||||
import { init } from '@utils/Sentry'
|
||||
import Logger from '@utils/Logger'
|
||||
import { systemTheme } from '@utils/Tools'
|
||||
import { parseCookie, systemTheme } from '@utils/Tools'
|
||||
import { shortcutKeyMap } from '@utils/Constants'
|
||||
import { Theme } from '@types'
|
||||
|
||||
@ -16,8 +16,6 @@ const Footer = dynamic(() => import('@components/Footer'))
|
||||
const Navbar = dynamic(() => import('@components/Navbar'))
|
||||
const Modal = dynamic(() => import('@components/Modal'))
|
||||
|
||||
import Crypto from 'crypto'
|
||||
|
||||
import 'core-js/es/promise'
|
||||
import 'core-js/es/set'
|
||||
import 'core-js/es/map'
|
||||
@ -26,7 +24,6 @@ import '../app.css'
|
||||
import '../github-markdown.css'
|
||||
import '@fortawesome/fontawesome-free/css/all.css'
|
||||
import PlatformDisplay from '@components/PlatformDisplay'
|
||||
|
||||
init()
|
||||
|
||||
// Progress Bar
|
||||
@ -35,14 +32,12 @@ Router.events.on('routeChangeStart', NProgress.start)
|
||||
Router.events.on('routeChangeComplete', NProgress.done)
|
||||
Router.events.on('routeChangeError', NProgress.done)
|
||||
|
||||
export default function App({ Component, pageProps, err }: KoreanbotsProps): JSX.Element {
|
||||
const [ betaKey, setBetaKey ] = useState('')
|
||||
const KoreanbotsApp = ({ Component, pageProps, err, cookie }: KoreanbotsProps): JSX.Element => {
|
||||
const [ shortcutModal, setShortcutModal ] = useState(false)
|
||||
const [ theme, setTheme ] = useState<Theme>('system')
|
||||
const router = useRouter()
|
||||
|
||||
useEffect(() => {
|
||||
setBetaKey(localStorage.betaKey)
|
||||
console.log(
|
||||
'%c' + 'KOREANBOTS',
|
||||
'color: #3366FF; -webkit-text-stroke: 2px black; font-size: 72px; font-weight: bold;'
|
||||
@ -71,16 +66,9 @@ export default function App({ Component, pageProps, err }: KoreanbotsProps): JSX
|
||||
<link rel='shortcut icon' href='/logo.png' />
|
||||
<meta name='theme-color' content='#3366FF' />
|
||||
</Head>
|
||||
<Navbar />
|
||||
<Navbar token={cookie.token} />
|
||||
<div className='iu-is-the-best min-h-screen text-black dark:text-gray-100 dark:bg-discord-dark bg-white'>
|
||||
{
|
||||
process.env.NEXT_PUBLIC_TESTER_KEY === Crypto.createHmac('sha256', betaKey ?? '').digest('hex') ?
|
||||
<Component {...pageProps} err={err} theme={theme} setTheme={setTheme} /> :
|
||||
<div className='text-center py-40 px-10'>
|
||||
<h1 className='text-3xl font-bold'>주어진 테스터키를 입력해주세요.</h1><br/>
|
||||
<input value={betaKey} name='field_name' className='text-black border outline-none px-4 py-2 rounded-2xl' type='text' placeholder='테스터 키' onChange={(e)=> { localStorage.setItem('betaKey', e.target.value); setBetaKey(e.target.value) }} />
|
||||
</div>
|
||||
}
|
||||
<Component {...pageProps} err={err} theme={theme} setTheme={setTheme} />
|
||||
</div>
|
||||
{
|
||||
!(router.pathname.startsWith('/developers')) && <Footer theme={theme} setTheme={setTheme} />
|
||||
@ -126,6 +114,20 @@ export default function App({ Component, pageProps, err }: KoreanbotsProps): JSX
|
||||
</div>
|
||||
}
|
||||
|
||||
KoreanbotsApp.getInitialProps = async (appCtx: AppContext) => {
|
||||
const appProps = await App.getInitialProps(appCtx)
|
||||
const parsed = parseCookie(appCtx.ctx.req)
|
||||
return {
|
||||
...appProps,
|
||||
cookie: parsed
|
||||
}
|
||||
}
|
||||
|
||||
export default KoreanbotsApp
|
||||
|
||||
interface KoreanbotsProps extends AppProps {
|
||||
err: unknown
|
||||
cookie: {
|
||||
token?: string
|
||||
}
|
||||
}
|
||||
19
pages/api/v2/users/@me.ts
Normal file
19
pages/api/v2/users/@me.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { NextApiRequest } from 'next'
|
||||
|
||||
import { get } from '@utils/Query'
|
||||
import ResponseWrapper from '@utils/ResponseWrapper'
|
||||
import RequestHandler from '@utils/RequestHandler'
|
||||
|
||||
const UserMe = RequestHandler().get(async (req: ApiRequest, res) => {
|
||||
const user = await get.Authorization(req.cookies.token)
|
||||
if (!user) return ResponseWrapper(res, { code: 401 })
|
||||
else return ResponseWrapper(res, { code: 200, data: await get.user.load(user) })
|
||||
})
|
||||
|
||||
interface ApiRequest extends NextApiRequest {
|
||||
query: {
|
||||
id: string
|
||||
}
|
||||
}
|
||||
|
||||
export default UserMe
|
||||
@ -1,62 +1,22 @@
|
||||
import { NextPage, NextPageContext } from 'next'
|
||||
import { NextPage} from 'next'
|
||||
import dynamic from 'next/dynamic'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
import { verify } from '@utils/Jwt'
|
||||
import { get } from '@utils/Query'
|
||||
import { parseCookie, redirectTo } from '@utils/Tools'
|
||||
import { User } from '@types'
|
||||
import { redirectTo } from '@utils/Tools'
|
||||
|
||||
const Loader = dynamic(() => import('@components/Loader'))
|
||||
|
||||
const DiscordCallback:NextPage<DiscordCallbackProps> = ({ data }) => {
|
||||
const DiscordCallback:NextPage = () => {
|
||||
const router = useRouter()
|
||||
const [ redirect, setRedirect ] = useState(false)
|
||||
useEffect(() => {
|
||||
if(!data) router.push('/api/auth/discord')
|
||||
else {
|
||||
localStorage.userCache = JSON.stringify({
|
||||
id: data.id,
|
||||
username: data.username,
|
||||
tag: data.tag,
|
||||
version: 2
|
||||
})
|
||||
setRedirect(true)
|
||||
}
|
||||
|
||||
}, [ data, router ])
|
||||
function redirectWhere() {
|
||||
redirectTo(router, localStorage.redirectTo ?? '/')
|
||||
localStorage.removeItem('redirectTo')
|
||||
return
|
||||
}
|
||||
if(!data) {
|
||||
return <div className='absolute right-1/2 bottom-1/2 text-center'>
|
||||
<h1 className='text-3xl text-bold'>리다이랙트중입니다.</h1>
|
||||
</div>
|
||||
}
|
||||
}, [router])
|
||||
|
||||
else return <>
|
||||
<Loader text={<>로그인중입니다. 잠시만 기다려주세요.<br />이 페이지가 계속 표시된다면 새로고침해주세요.</>} />
|
||||
{
|
||||
redirect ? redirectWhere() : ''
|
||||
}
|
||||
return <>
|
||||
<Loader text={<>리다이랙트 중 입니다.</>} />
|
||||
</>
|
||||
}
|
||||
|
||||
export const getServerSideProps = async(ctx: NextPageContext) => {
|
||||
const parsed = parseCookie(ctx.req)
|
||||
const token = verify(parsed?.token ?? '')
|
||||
if(!token) return { props: { data: null } }
|
||||
|
||||
const userinfo = await get.user.load(token.id)
|
||||
|
||||
return { props: { data: userinfo } }
|
||||
}
|
||||
|
||||
interface DiscordCallbackProps {
|
||||
data: User | null
|
||||
}
|
||||
|
||||
export default DiscordCallback
|
||||
Loading…
x
Reference in New Issue
Block a user