mirror of
https://github.com/koreanbots/core.git
synced 2025-12-16 22:30:23 +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/click-events-have-key-events */
|
||||||
/* eslint-disable jsx-a11y/no-noninteractive-tabindex */
|
/* eslint-disable jsx-a11y/no-noninteractive-tabindex */
|
||||||
/* eslint-disable jsx-a11y/no-static-element-interactions */
|
/* eslint-disable jsx-a11y/no-static-element-interactions */
|
||||||
import { useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
|
|
||||||
import { redirectTo } from '@utils/Tools'
|
import { redirectTo } from '@utils/Tools'
|
||||||
import { UserCache } from '@types'
|
import { User, UserCache } from '@types'
|
||||||
|
|
||||||
import DiscordAvatar from '@components/DiscordAvatar'
|
import DiscordAvatar from '@components/DiscordAvatar'
|
||||||
|
import Fetch from '@utils/Fetch'
|
||||||
|
|
||||||
const Navbar = (): JSX.Element => {
|
const Navbar = ({ token }:{ token: string }): JSX.Element => {
|
||||||
let userCache:UserCache
|
const [userCache, setUserCache] = useState<UserCache>()
|
||||||
try {
|
|
||||||
userCache = JSON.parse(localStorage.userCache)
|
|
||||||
} catch {
|
|
||||||
userCache = null
|
|
||||||
}
|
|
||||||
|
|
||||||
const [navbarOpen, setNavbarOpen] = useState<boolean>(false)
|
const [navbarOpen, setNavbarOpen] = useState<boolean>(false)
|
||||||
const [dropdownOpen, setDropdownOpen] = useState<boolean>(false)
|
const [dropdownOpen, setDropdownOpen] = useState<boolean>(false)
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const logged = userCache?.id && userCache.version === 2
|
const logged = userCache?.id && userCache.version === 2
|
||||||
const dev = router.pathname.startsWith('/developers')
|
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 (
|
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'>
|
<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 Head from 'next/head'
|
||||||
import type { AppProps } from 'next/app'
|
import App, { AppContext, AppProps } from 'next/app'
|
||||||
import dynamic from 'next/dynamic'
|
import dynamic from 'next/dynamic'
|
||||||
import { Router, useRouter } from 'next/router'
|
import { Router, useRouter } from 'next/router'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
@ -8,7 +8,7 @@ import NProgress from 'nprogress'
|
|||||||
|
|
||||||
import { init } from '@utils/Sentry'
|
import { init } from '@utils/Sentry'
|
||||||
import Logger from '@utils/Logger'
|
import Logger from '@utils/Logger'
|
||||||
import { systemTheme } from '@utils/Tools'
|
import { parseCookie, systemTheme } from '@utils/Tools'
|
||||||
import { shortcutKeyMap } from '@utils/Constants'
|
import { shortcutKeyMap } from '@utils/Constants'
|
||||||
import { Theme } from '@types'
|
import { Theme } from '@types'
|
||||||
|
|
||||||
@ -16,8 +16,6 @@ const Footer = dynamic(() => import('@components/Footer'))
|
|||||||
const Navbar = dynamic(() => import('@components/Navbar'))
|
const Navbar = dynamic(() => import('@components/Navbar'))
|
||||||
const Modal = dynamic(() => import('@components/Modal'))
|
const Modal = dynamic(() => import('@components/Modal'))
|
||||||
|
|
||||||
import Crypto from 'crypto'
|
|
||||||
|
|
||||||
import 'core-js/es/promise'
|
import 'core-js/es/promise'
|
||||||
import 'core-js/es/set'
|
import 'core-js/es/set'
|
||||||
import 'core-js/es/map'
|
import 'core-js/es/map'
|
||||||
@ -26,7 +24,6 @@ import '../app.css'
|
|||||||
import '../github-markdown.css'
|
import '../github-markdown.css'
|
||||||
import '@fortawesome/fontawesome-free/css/all.css'
|
import '@fortawesome/fontawesome-free/css/all.css'
|
||||||
import PlatformDisplay from '@components/PlatformDisplay'
|
import PlatformDisplay from '@components/PlatformDisplay'
|
||||||
|
|
||||||
init()
|
init()
|
||||||
|
|
||||||
// Progress Bar
|
// Progress Bar
|
||||||
@ -35,14 +32,12 @@ Router.events.on('routeChangeStart', NProgress.start)
|
|||||||
Router.events.on('routeChangeComplete', NProgress.done)
|
Router.events.on('routeChangeComplete', NProgress.done)
|
||||||
Router.events.on('routeChangeError', NProgress.done)
|
Router.events.on('routeChangeError', NProgress.done)
|
||||||
|
|
||||||
export default function App({ Component, pageProps, err }: KoreanbotsProps): JSX.Element {
|
const KoreanbotsApp = ({ Component, pageProps, err, cookie }: KoreanbotsProps): JSX.Element => {
|
||||||
const [ betaKey, setBetaKey ] = useState('')
|
|
||||||
const [ shortcutModal, setShortcutModal ] = useState(false)
|
const [ shortcutModal, setShortcutModal ] = useState(false)
|
||||||
const [ theme, setTheme ] = useState<Theme>('system')
|
const [ theme, setTheme ] = useState<Theme>('system')
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setBetaKey(localStorage.betaKey)
|
|
||||||
console.log(
|
console.log(
|
||||||
'%c' + 'KOREANBOTS',
|
'%c' + 'KOREANBOTS',
|
||||||
'color: #3366FF; -webkit-text-stroke: 2px black; font-size: 72px; font-weight: bold;'
|
'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' />
|
<link rel='shortcut icon' href='/logo.png' />
|
||||||
<meta name='theme-color' content='#3366FF' />
|
<meta name='theme-color' content='#3366FF' />
|
||||||
</Head>
|
</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'>
|
<div className='iu-is-the-best min-h-screen text-black dark:text-gray-100 dark:bg-discord-dark bg-white'>
|
||||||
{
|
<Component {...pageProps} err={err} theme={theme} setTheme={setTheme} />
|
||||||
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>
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
{
|
{
|
||||||
!(router.pathname.startsWith('/developers')) && <Footer theme={theme} setTheme={setTheme} />
|
!(router.pathname.startsWith('/developers')) && <Footer theme={theme} setTheme={setTheme} />
|
||||||
@ -126,6 +114,20 @@ export default function App({ Component, pageProps, err }: KoreanbotsProps): JSX
|
|||||||
</div>
|
</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 {
|
interface KoreanbotsProps extends AppProps {
|
||||||
err: unknown
|
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 dynamic from 'next/dynamic'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect } from 'react'
|
||||||
|
|
||||||
import { verify } from '@utils/Jwt'
|
import { redirectTo } from '@utils/Tools'
|
||||||
import { get } from '@utils/Query'
|
|
||||||
import { parseCookie, redirectTo } from '@utils/Tools'
|
|
||||||
import { User } from '@types'
|
|
||||||
|
|
||||||
const Loader = dynamic(() => import('@components/Loader'))
|
const Loader = dynamic(() => import('@components/Loader'))
|
||||||
|
|
||||||
const DiscordCallback:NextPage<DiscordCallbackProps> = ({ data }) => {
|
const DiscordCallback:NextPage = () => {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const [ redirect, setRedirect ] = useState(false)
|
|
||||||
useEffect(() => {
|
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 ?? '/')
|
redirectTo(router, localStorage.redirectTo ?? '/')
|
||||||
localStorage.removeItem('redirectTo')
|
localStorage.removeItem('redirectTo')
|
||||||
return
|
}, [router])
|
||||||
}
|
|
||||||
if(!data) {
|
|
||||||
return <div className='absolute right-1/2 bottom-1/2 text-center'>
|
|
||||||
<h1 className='text-3xl text-bold'>리다이랙트중입니다.</h1>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
else return <>
|
return <>
|
||||||
<Loader text={<>로그인중입니다. 잠시만 기다려주세요.<br />이 페이지가 계속 표시된다면 새로고침해주세요.</>} />
|
<Loader text={<>리다이랙트 중 입니다.</>} />
|
||||||
{
|
|
||||||
redirect ? redirectWhere() : ''
|
|
||||||
}
|
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
export default DiscordCallback
|
||||||
Loading…
x
Reference in New Issue
Block a user