1.login의 최종 page.
2. 위에서 다루었던, useMutaion, useSWR, withHandler, withSession,
react-hook-form등을 종합해서 최종적으로 만드는
login page(pages/enter.tsx)
3. NEXTJS의 login 최종 마무리
import { useEffect, useState } from 'react'
import type { NextPage } from 'next'
import Input from '../components/input'
import Button from '../components/button'
import { useForm } from 'react-hook-form'
import useMutation from '../libs/client/useMutation'
import { useRouter } from 'next/router'
function cls(...classnames: string[]) {
return classnames.join('')
}
interface EnterForm {
email?: string
phone?: string
}
///EnertForm의 argument type설정해줌.
interface TokenForm {
token: string
}
///TokenForm의 argument type설정해줌.
interface MutationResult {
ok: boolean
payload: string
}
///MutationResult Type설정
export function Enter() {
const [enter, { loading, data, error }] =
useMutation<MutationResult>('/api/users/enter')
///useMutation hook을 이용해서 '/api/users/enter' API로
///EnterForm에서 입력받은 data(email, phone)을 보내고,
///data(ok, payload)를 받음.
///enter은 이 useMutation의 이름.
///data를 보내는거는 밑은 const onValid에서 처리됨.
const [
confirmToken,
{ loading: tokenLoading, data: tokenData, error: tokenError },
] = useMutation<MutationResult>('/api/users/confirm')
///위 enter useMutation을 실행 후, 받은 payload(token)을 압력하고
///나면, 실행시킬 useMutation.
///단어가 겹치면 error가 나서 tokenLoading, tokenData, tokenError로
///rename한다.
///'api/users/confirm' API로 요청을 보냄.
///useMutation뒤에 <useMutaitonResult>로 type을 설정해줌.
const { register, reset, handleSubmit } = useForm<EnterForm>()
///email, phone 입력하는 useForm, type <EnterForm>설정해줌.
///form을 다루는 react-hook-form
const { register: tokenRegister, handleSubmit: tokenHandleSubmit } =
useForm<TokenForm>()
///email 혹은 phone을 입력해서 받은 toeken을 입력하는 form
///<TokenForm>으로 타입 설정해줌.
///register등등이 이름이 겹쳐서 rename해 줌.
const [method, setMethod] = useState<'email' | 'phone'>('email')
const onEmailClick = () => {
reset(), setMethod('email')
}
const onPhoneClick = () => {
reset(), setMethod('phone')
}
const onValid = (validForm: EnterForm) => {
if (loading) return
enter(validForm)
}
///밑의 EnterForm에서 받은 data를
///enter useMutation을 이용해서 data를 넣어서
/// api/users/enter로 보내줌.
console.log(data)
const onTokenValid = (validForm: TokenForm) => {
confirmToken(validForm)
}
///밑의 TokenForm에서 받은 data를 confirm useMutation에
///data(validForm)를 넣어서
/// /api/users/confirm/으로 날려줌.
///onSubmint={handleSubmit()}에서 이름겹쳐서
/// 위에는 onValid 밑에는 onTokenValid로 설정해줌.
const router = useRouter()
useEffect(() => {
if (tokenData?.ok) {
router.push('/')
}
}, [tokenData, router])
///confirm useMutation 사용 후, tokenData를 받아서,
///tokenData에 ok가 있으면, localhost:3000/ path로 날려줌.
return (
<div className="mt-16 px-4">
<h1>{data?.payload}</h1>
<h3 className="text-3xl font-bold text-center">Enter to Apple Market</h3>
<div className="mt-16">
{data?.ok ? ( ///enter useMutation실행후, ok받으면, 아래꺼 나오게~
<form
onSubmit={tokenHandleSubmit(onTokenValid)} ///이해하겠쥬~
className="flex flex-col mt-8 space-y-4 mx-5"
>
<Input ///Input component에 register를 prop으로 보내는 방법
register={tokenRegister('token', {
required: true,
minLength: 5,
})}
name="token"
label="Confirm Token"
type="number"
required
/>
<Button text={tokenLoading ? 'loaindg' : 'Confirm Token'} />
</form>
) : ( ///phone, emial 입력하는 form!!
<>
{' '}
<div className="flex flex-col items-center">
<h5 className="text-sm text-gray-500 font-medium">
Enter using:
</h5>
<div className="grid grid-cols-2 gap-10 mt-8 border-b w-full pb-2">
<button
className={cls( ///cls사용예시!!!!!!!!!!!!
'pb-4 font-medium border-b-2',
method === 'email'
? ' border-red-500 text-red-500'
: ' border-transparent hover:text-gray-400 '
)}
onClick={onEmailClick}
>
Email
</button>
<button
className={cls(
'pb-4 border-b-2 font-medium',
method === 'phone'
? ' border-red-500 text-red-500'
: ' border-transparent hover:text-gray-400 '
)}
onClick={onPhoneClick}
>
Phone
</button>
</div>
</div>
<form
onSubmit={handleSubmit(onValid)}
className="flex flex-col mt-8 space-y-4 mx-5"
>
{method === 'email' ? (
<Input ///Input component에 prop보내줌. register유심히 볼것
register={register('email', { required: true, minLength: 5 })}
name="email"
label="Email address"
type="email"
required
/>
) : null}
{method === 'phone' ? (
<Input ///Input component에 prop보내줌. register유심히 볼것
register={register('phone', { required: true, minLength: 5 })}
name="phone"
label="phone number"
type="number"
kind="phone"
required
/>
) : null}
{method === 'email' ? (
<Button text={loading ? 'loaindg' : 'Get login link'} />
) : null}
{method === 'phone' ? (
<Button text={loading ? 'loading' : 'Get one-time password'} />
) : null}
</form>
</>
)}
<div className="mt-6 relative">
<div className="absolute w-full border-t border-gray-300" />
<div className="relative -top-8 flex items-center justify-center">
<span className="mt-5 bg-white text-gray-500 px-2">
Or Enter With
</span>
</div>
</div>
</div>
</div>
)
}
export default Enter
NOTICE!!
이걸로 authenticate authorization 마무리
애럽다 애러버~
참고로 auth를 무척 쉽게, git, facebook, google등의 계정을 가져다 쓸 수 있게 만들어 놓음.
아래 site참고할만함.
https://next-auth.js.org/