update
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
package org.egovframe.cloud.userservice.api.user.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.api.user.dto.SocialUserRequestDto
|
||||
*
|
||||
* 소셜 사용자 요청 DTO 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/10/22
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/10/22 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
public class SocialUserRequestDto {
|
||||
|
||||
/**
|
||||
* 공급자
|
||||
*/
|
||||
private String provider;
|
||||
|
||||
/**
|
||||
* 토큰
|
||||
*/
|
||||
private String token;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package org.egovframe.cloud.userservice.api.user.dto;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.api.user.dto.SocialUserResponseDto
|
||||
* <p>
|
||||
* 소셜 사용자 응답 DTO 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/10/22
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/10/22 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
public class SocialUserResponseDto {
|
||||
|
||||
/**
|
||||
* 아이디
|
||||
*/
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 이메일
|
||||
*/
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 이름
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 소셜 사용자 DTO 클래스 생성자
|
||||
* 빌더 패턴으로 객체 생성
|
||||
*
|
||||
* @param id 아이디
|
||||
* @param email 이메일
|
||||
* @param name 이름
|
||||
*/
|
||||
@Builder
|
||||
public SocialUserResponseDto(String id, String email, String name) {
|
||||
this.id = id;
|
||||
this.email = email;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -36,6 +36,7 @@ const App = ({ component: Component, ...pageProps }: AppProps) => {
|
||||
const router = useRouter()
|
||||
const pathname = router.pathname
|
||||
const authPage = pathname?.startsWith('/auth/')
|
||||
const naverLoginCallbackPage = pathname?.startsWith('/auth/login/naver')
|
||||
const errorPage = router.pathname === '/404' || router.pathname === '/_error'
|
||||
|
||||
const { enqueueSnackbar } = useSnackbar()
|
||||
@@ -127,7 +128,7 @@ const App = ({ component: Component, ...pageProps }: AppProps) => {
|
||||
return null
|
||||
}
|
||||
|
||||
return errorPage ? (
|
||||
return errorPage || naverLoginCallbackPage ? (
|
||||
<Wrapper>
|
||||
<Component {...pageProps} />
|
||||
</Wrapper>
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
import React, { useState } from 'react'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import KakaoLogin from 'react-kakao-login'
|
||||
import { KAKAO_JAVASCRIPT_KEY } from '@constants/env'
|
||||
import { ISocialButton } from '@components/Buttons/GoogleLoginButton'
|
||||
import CustomConfirm, { CustomConfirmPrpps } from '@components/CustomConfirm'
|
||||
|
||||
const KakaoLoginButton = (props: ISocialButton) => {
|
||||
const { handleClick, confirmMessage } = props
|
||||
export interface ISocialKakaoButton extends ISocialButton {
|
||||
kakaoLoginMode?: string
|
||||
setKakaoLoginMode?: any
|
||||
}
|
||||
|
||||
const KakaoLoginButton = (props: ISocialKakaoButton) => {
|
||||
const { handleClick, confirmMessage, kakaoLoginMode, setKakaoLoginMode } = props
|
||||
const { t } = useTranslation()
|
||||
|
||||
const [customConfirm, setCustomConfirm] = useState<CustomConfirmPrpps>({
|
||||
@@ -15,6 +20,23 @@ const KakaoLoginButton = (props: ISocialButton) => {
|
||||
handleCancel: () => {},
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
// 라이브러리에서 로그인 상태를 유지하고 바꿀 수 없어서 이런 코드를..
|
||||
if (kakaoLoginMode !== 'logout' || !document || !document.querySelector('#kakaoIdLogin')) {
|
||||
return
|
||||
}
|
||||
|
||||
const kakaoLoginButton = document.querySelector('#kakaoIdLogin')
|
||||
|
||||
// @ts-ignore
|
||||
kakaoLoginButton.href = 'javascript:void(0);'
|
||||
|
||||
// @ts-ignore
|
||||
kakaoLoginButton.click()
|
||||
|
||||
setKakaoLoginMode(null)
|
||||
}, [kakaoLoginMode])
|
||||
|
||||
return (
|
||||
<>
|
||||
<KakaoLogin
|
||||
@@ -24,6 +46,7 @@ const KakaoLoginButton = (props: ISocialButton) => {
|
||||
render={(_props: any) => (
|
||||
<a
|
||||
href="#"
|
||||
id="kakaoIdLogin"
|
||||
className="social kakao"
|
||||
onClick={event => {
|
||||
event.preventDefault()
|
||||
|
||||
@@ -47,6 +47,7 @@ const NaverLoginButton = (loginButtonProps: ISocialButton) => {
|
||||
})
|
||||
|
||||
naverLogin.init()
|
||||
|
||||
if (!window.opener) {
|
||||
naver.successCallback = data => {
|
||||
return onSuccess(data)
|
||||
@@ -91,7 +92,6 @@ const NaverLoginButton = (loginButtonProps: ISocialButton) => {
|
||||
}
|
||||
|
||||
const loadScript = useCallback(() => {
|
||||
if (mounted) {
|
||||
if (
|
||||
document &&
|
||||
document.querySelectorAll('#naver-login-sdk').length === 0
|
||||
@@ -106,13 +106,14 @@ const NaverLoginButton = (loginButtonProps: ISocialButton) => {
|
||||
} else {
|
||||
initLoginButton()
|
||||
}
|
||||
}
|
||||
}, [mounted])
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (mounted) {
|
||||
appendNaverButton()
|
||||
loadScript()
|
||||
}, [])
|
||||
}
|
||||
}, [mounted])
|
||||
|
||||
const handleLogin = () => {
|
||||
if (!document || !document.querySelector('#naverIdLogin').firstChild) {
|
||||
|
||||
@@ -70,7 +70,7 @@ export default async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
|
||||
res.status(200).json(payload)
|
||||
} else {
|
||||
res.status(401).json({ message: 'Invalid Credentials 🥺' })
|
||||
res.status(result.status).json({ message: 'Invalid Credentials 🥺' })
|
||||
}
|
||||
} else {
|
||||
res.status(401).json({ message: 'Invalid Credentials 🥺' })
|
||||
|
||||
@@ -2,12 +2,13 @@ import CustomAlert, { CustomAlertPrpps } from '@components/CustomAlert'
|
||||
import { DLWrapper } from '@components/WriteDLFields'
|
||||
import { makeStyles, Theme } from '@material-ui/core/styles'
|
||||
import Alert from '@material-ui/lab/Alert'
|
||||
import { userService } from '@service'
|
||||
import { ISocialUser, userService } from '@service'
|
||||
import { format, isValidPassword } from '@utils'
|
||||
import { useRouter } from 'next/router'
|
||||
import React, { createRef, useState } from 'react'
|
||||
import React, { createRef, useEffect, useState } from 'react'
|
||||
import { Controller, useForm } from 'react-hook-form'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { GetServerSideProps } from 'next'
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) => ({
|
||||
alert: {
|
||||
@@ -20,9 +21,17 @@ interface IUserForm {
|
||||
password: string
|
||||
passwordConfirm: string
|
||||
userName: string
|
||||
provider?: string
|
||||
token?: string
|
||||
}
|
||||
|
||||
const Form = () => {
|
||||
interface FormProps {
|
||||
socialUser: ISocialUser
|
||||
}
|
||||
|
||||
const Form = (props: FormProps) => {
|
||||
const { socialUser } = props
|
||||
|
||||
const router = useRouter()
|
||||
const classes = useStyles()
|
||||
const { t } = useTranslation()
|
||||
@@ -44,10 +53,12 @@ const Form = () => {
|
||||
// form hook
|
||||
const methods = useForm<IUserForm>({
|
||||
defaultValues: {
|
||||
email: '',
|
||||
email: socialUser.email || '',
|
||||
password: '',
|
||||
passwordConfirm: '',
|
||||
userName: '',
|
||||
userName: socialUser.name || '',
|
||||
provider: router.query.provider as string,
|
||||
token: router.query.token as string,
|
||||
},
|
||||
})
|
||||
const {
|
||||
@@ -67,6 +78,14 @@ const Form = () => {
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (socialUser) {
|
||||
if (socialUser.name) {
|
||||
|
||||
}
|
||||
}
|
||||
}, [socialUser])
|
||||
|
||||
// 이메일중복확인
|
||||
const handleCheckEmail = event => {
|
||||
event.preventDefault()
|
||||
@@ -156,6 +175,7 @@ const Form = () => {
|
||||
<input
|
||||
ref={emailRef}
|
||||
type="text"
|
||||
readOnly={/*typeof socialUser.email !== 'undefined' && socialUser.email !== null*/false}
|
||||
value={field.value}
|
||||
onChange={field.onChange}
|
||||
placeholder={t('user.email')}
|
||||
@@ -264,6 +284,7 @@ const Form = () => {
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
readOnly={/*typeof socialUser.name !== 'undefined' && socialUser.name !== null*/false}
|
||||
value={field.value}
|
||||
onChange={field.onChange}
|
||||
placeholder={t('label.title.name')}
|
||||
@@ -310,4 +331,33 @@ const Form = () => {
|
||||
)
|
||||
}
|
||||
|
||||
export const getServerSideProps: GetServerSideProps = async context => {
|
||||
const provider = context.query.provider as string
|
||||
const token = context.query.token as string
|
||||
|
||||
let socialUser = {}
|
||||
|
||||
try {
|
||||
if (provider && token) {
|
||||
const result = await userService.social(provider, token)
|
||||
if (result) {
|
||||
socialUser = (await result.data) as ISocialUser
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`social item query error ${error.message}`)
|
||||
if (error.response?.data?.code === 'E003') {
|
||||
return {
|
||||
notFound: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
props: {
|
||||
socialUser
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export default Form
|
||||
|
||||
@@ -61,7 +61,7 @@ const Join = ({ policyPP, policyTOS }: IJoinProps) => {
|
||||
return
|
||||
}
|
||||
|
||||
router.push('/auth/join/form')
|
||||
router.push(`/auth/join/form?provider=${router.query.provider}&token=${router.query.token}`)
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -9,17 +9,26 @@ import Loader from '@components/Loader'
|
||||
import useUser from '@hooks/useUser'
|
||||
import { ILogin, loginSerivce } from '@service'
|
||||
import { userAtom } from '@stores'
|
||||
import Router from 'next/router'
|
||||
import Router, { useRouter } from 'next/router'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useRecoilValue } from 'recoil'
|
||||
import CustomConfirm, { CustomConfirmPrpps } from '@components/CustomConfirm'
|
||||
|
||||
interface AlertProps extends CustomConfirmPrpps {
|
||||
message: string
|
||||
}
|
||||
|
||||
const Login = () => {
|
||||
const { t } = useTranslation()
|
||||
const router = useRouter()
|
||||
|
||||
const { isLogin, mutate } = useUser()
|
||||
const user = useRecoilValue(userAtom)
|
||||
|
||||
const [customConfirm, setCustomConfirm] = useState<AlertProps | null>(null)
|
||||
const [errorState, setErrorState] = useState<string | null>(null)
|
||||
const [kakaoLoginMode, setKakaoLoginMode] = useState<string | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
if (isLogin && user) {
|
||||
@@ -42,9 +51,31 @@ const Login = () => {
|
||||
setErrorState(result)
|
||||
}
|
||||
} catch (error) {
|
||||
if (error === 'join') {
|
||||
setCustomConfirm({
|
||||
open: true,
|
||||
message: t('msg.confirm.join.social'),
|
||||
handleConfirm: () => {
|
||||
setCustomConfirm({
|
||||
...customConfirm,
|
||||
open: false,
|
||||
})
|
||||
|
||||
// recoil 쓰려했는데 회원가입에 스탭이 있어서 진행중에 새로고침하면 상태가 삭제되면서 일반회원으로 가입될 수 있어서 소셜 정보를 파라미터로 넘김
|
||||
router.push(`/auth/join?provider=${data.provider}&token=${data.token}`)
|
||||
},
|
||||
handleCancel: () => {
|
||||
if (data.provider === 'kakao') {
|
||||
setKakaoLoginMode('logout')
|
||||
}
|
||||
setCustomConfirm({ ...customConfirm, open: false })
|
||||
},
|
||||
})
|
||||
} else {
|
||||
setErrorState(t('err.user.login'))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 이메일 로그인
|
||||
const handleLoginSubmit = async (form: loginFormType) => {
|
||||
@@ -105,11 +136,19 @@ const Login = () => {
|
||||
<span>{t('label.title.login.oauth')}</span>
|
||||
</h3>
|
||||
<div>
|
||||
<KakaoLoginButton handleClick={handleKakaoLogin} />
|
||||
<KakaoLoginButton handleClick={handleKakaoLogin} kakaoLoginMode={kakaoLoginMode} setKakaoLoginMode={setKakaoLoginMode} />
|
||||
<NaverLoginButton handleClick={handleNaverLogin} />
|
||||
<GoogleLoginButton handleClick={handleGoogleLogin} />
|
||||
</div>
|
||||
</article>
|
||||
{customConfirm && (
|
||||
<CustomConfirm
|
||||
handleConfirm={customConfirm.handleConfirm}
|
||||
handleCancel={customConfirm.handleCancel}
|
||||
contentText={customConfirm.message}
|
||||
open={customConfirm.open}
|
||||
/>
|
||||
)}
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ const LoginNaver = () => {
|
||||
|
||||
return <></> */
|
||||
|
||||
return <NaverLoginButton handleClick={() => {}} />
|
||||
return <div style={{ display: 'none' }}><NaverLoginButton handleClick={() => {}} /></div>
|
||||
}
|
||||
|
||||
export default LoginNaver
|
||||
|
||||
@@ -150,9 +150,8 @@ const UserInfo = () => {
|
||||
token: response.response.access_token,
|
||||
},
|
||||
})
|
||||
setErrorState(null)
|
||||
} else {
|
||||
setErrorState(t('err.user.login.social'))
|
||||
setErrorState({ message: t('err.user.login.social') })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,9 +172,8 @@ const UserInfo = () => {
|
||||
token: response.accessToken,
|
||||
},
|
||||
})
|
||||
setErrorState(null)
|
||||
} else {
|
||||
setErrorState(t('err.user.login.social'))
|
||||
setErrorState({ message: t('err.user.login.social') })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,9 +191,8 @@ const UserInfo = () => {
|
||||
token: response.tokenId,
|
||||
},
|
||||
})
|
||||
setErrorState(null)
|
||||
} else {
|
||||
setErrorState(t('err.user.login.social'))
|
||||
setErrorState({ message: t('err.user.login.social') })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,8 @@ export const loginSerivce = {
|
||||
if (result.status === 200) {
|
||||
onSuccessLogin(await result.json())
|
||||
resolve('success')
|
||||
} if (result.status === 412) {
|
||||
reject('join')
|
||||
} else {
|
||||
reject('noAuth')
|
||||
}
|
||||
|
||||
@@ -38,10 +38,19 @@ interface IUserUpdate extends IVerification {
|
||||
userName: string
|
||||
}
|
||||
|
||||
// 소셜 정보
|
||||
export interface ISocialUser {
|
||||
id: string
|
||||
email: string
|
||||
name: string
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 관리 서비스
|
||||
*/
|
||||
export const userService = {
|
||||
social: (provider: string, token: string) =>
|
||||
axios.post(`${USER_URL}/social`, { provider, token }),
|
||||
existsEmail: (email: string, userId?: string) =>
|
||||
new Promise<boolean>((resolve, rejects) => {
|
||||
axios
|
||||
|
||||
Reference in New Issue
Block a user