enter page

김종민·2022년 8월 3일
0

apple-market

목록 보기
16/37


1.login의 최종 page.
2. 위에서 다루었던, useMutaion, useSWR, withHandler, withSession,
react-hook-form등을 종합해서 최종적으로 만드는
login page(pages/enter.tsx)
3. NEXTJS의 login 최종 마무리

1. pages/enter.tsx

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 마무리
애럽다 애러버~

2. nextAuth

참고로 auth를 무척 쉽게, git, facebook, google등의 계정을 가져다 쓸 수 있게 만들어 놓음.
아래 site참고할만함.
https://next-auth.js.org/

profile
코딩하는초딩쌤

0개의 댓글