Login, CreateAccount, useMe

김종민·2022년 9월 15일
0

Nuber-Client

목록 보기
6/21


지금까지의 설명을 바탕으로 login, createAccount를 완성한다.
그리고 어느page에서든지 사용될 useMe 함수를
hook에 만들어 놓는다.

1. src/hooks/useMe.tsx

import { gql, useQuery } from '@apollo/client'
import { MeQuery } from '../graphql/__generated__'

///serve의 me query를 front에서 사용.
export const ME_QUERY = gql`
  query me {
    me {
      id
      email
      role
    }
  }
`
///여기까지 작성후 npm run start(generate:codegen)를
///실행시켜야 밑에서 type인<MeQuery>가 생성되어 
///사용가능하다.

export const useMe = () => {
///useQuery를 사용해서 ME_QUERY를 실행시키고, 
///받아온 data를 return한다.
  return useQuery<MeQuery>(ME_QUERY)
}

2. src/constant.ts

export const LOCALSTORAGE_TOKEN = 'eat-token'

localstorage에 token을 담기 위해서 key를 하나 만든다.

3.src/pages/login.tsx

import { gql, useMutation } from '@apollo/client'
import React from 'react'
import { useForm } from 'react-hook-form'
import { Link } from 'react-router-dom'
import { authTokenVar, isLoggedInVar } from '../apollo'
import Button from '../components/button'
import { FormError } from '../components/form-error'
import { LoginMutation, LoginMutationVariables } from '../graphql/__generated__'
import { LOCALSTORAGE_TOKEN } from '../constant'

interface ILoginForm {
  email: string
  password: string
}
///login에 사용될 state들의 type을 설정한다.

const LOGIN_MUTATION = gql`
  mutation login($loginInput: LoginInput!) {
    login(input: $loginInput) {
      ok
      token
      error
    }
  }
`
///client에서 사용하기 위해서 server에서 login mutation을
///불러들인다. LoginInput!은 server의 dto임.
///이 과정을 거친 후 , 반드시 npm run start(codegen)를 
///실행해야 useMutation<>에 들어갈 type이 생성된다.
///생성되는 type은 LoginMutation,  LoginMutationVariables

export const Login = () => {
  const {
    register,
    getValues,
    formState: { errors, isValid },
    handleSubmit,
  } = useForm<ILoginForm>({
    mode: 'onChange',
  })
  ///react-hook-form

  const onCompleted = (data: LoginMutation) => {
    const {
      login: { ok, token },
    } = data
    if (ok && token) {
      console.log(token)
      localStorage.setItem(LOCALSTORAGE_TOKEN, token)
      authTokenVar(token)
      isLoggedInVar(true)
    }
  }
  ///loginMutaion실행 후, 받아온 data를 
  ///data중에 token을 LOCALSTORAGE_TOKEN에 담아주고
  ///authTokenVar에 담아주고
  ///isLoggedInVar를 true로 바꿔주는 함수.
  ///data:LoginMutaion은 바로 밑에서 넣어준 type

  const [loginMutation, { data: loginMutationResult, loading }] = useMutation<
    LoginMutation,
    LoginMutationVariables
  >(LOGIN_MUTATION, { onCompleted })
  ///맨처음에 만든 mutation을 실행시킬
  ///loginMutation함수임.

  const onSubmit = () => {
    if (!loading) {
      const { email, password } = getValues()
      loginMutation({
        variables: {
          loginInput: {
            email,
            password,
          },
        },
      })
    }
  }
  ///login 버튼을 누르면, form에서 받아온 
  ///password, email을 loginMutation 의 
  ///variables로 보내주고, 실행시킴.

  return (
    <div className="h-screen flex items-center justify-center flex-col">
      <div className="w-full max-w-screen-sm flex flex-col px-5 items-center">
        <h3 className="w-full font-medium text-left text-3xl mb-5">
          Welcome Back
        </h3>
        <form
          onSubmit={handleSubmit(onSubmit)}
          className="grid gap-3 mt-3 mb-5 w-full"
        >
          <input
            {...register('email', {
              required: 'Email is required',
              maxLength: { value: 30, message: 'max char is 30' },
            })}
            required
            maxLength={30}
            type="email"
            placeholder="Email"
            className="input"
          />
          {errors.email?.message && (
            <FormError errorMessage={errors.email.message} />
          )}
          <input
            {...register('password', { required: 'Password is required' })}
            name="password"
            type="password"
            placeholder="Password"
            className="input"
          />
          {errors.password?.message && (
            <FormError errorMessage={errors.password?.message} />
          )}
          <Button loading={loading} actionText="Login" />
          {loginMutationResult?.login.error && (
            <FormError errorMessage={loginMutationResult?.login.error} />
          )}
        </form>
        <p className="text-center mt-5 text-base">
          계정이 없으신가요?
          <Link
            to="/signup"
            className="ml-2 font-semibold text-green-600 hover:underline"
          >
          ///계정이 없으면, create-account page로 이동시킴.
            회원가입
          </Link>
        </p>
      </div>
    </div>
  )
}

4. src/pages/create-account.tsx

import { gql, useMutation } from '@apollo/client'
import React from 'react'
import { useForm } from 'react-hook-form'
import { Link } from 'react-router-dom'
import { useNavigate } from 'react-router-dom'
import Button from '../components/button'
import { FormError } from '../components/form-error'
import {
  CreateAccoountMutation,
  CreateAccoountMutationVariables,
  UserRole,
} from '../graphql/__generated__'

export const CREATE_ACCOUNT = gql`
  mutation createAccoount($createAccountInput: CreateAccountInput!) {
    createAccount(input: $createAccountInput) {
      ok
      error
    }
  }
`
///server에서 createAccount불러들임.
///여기까지 코딩하고 npm run start

interface ICreateAccountForm {
  email: string
  password: string
  role: UserRole
}
///입력받는 state의 type.

export const CreateAccount = () => {
  const {
    register,
    getValues,
    formState: { errors, isValid },
    handleSubmit,
  } = useForm<ICreateAccountForm>({
    mode: 'onChange',
    defaultValues: { role: UserRole.Client },
  })
  ///react-hook-form.
  ///role의 default 값은 Client로 한다.

  const navigate = useNavigate()
  ///계정을 만들면, login페이지로 이동시키기 위해
  ///useNavigate를 사용함.
  
  const onCompleted = (data: CreateAccoountMutation) => {
    const {
      createAccount: { ok },
    } = data
    if (ok) {
      alert('Account Created. Log in now.')
      navigate('/')
      ///createAccount를 실행하고
      ///ok를 받으면, alert를 띄우고,'/'페이지로 
      ///redirect한다.
    }
  }
  const [createAccountMutation, { loading, data: createAccountMutaionResult }] =
    useMutation<CreateAccoountMutation, CreateAccoountMutationVariables>(
      CREATE_ACCOUNT,
      { onCompleted }
    )
    
    ///getValues로 form의 data를 받아와서
    ///createAccountMutation의 variables에 넣어서
    ///실행시킨다.
  const onSubmit = () => {
    if (!loading) {
      const { email, password, role } = getValues()
      createAccountMutation({
        variables: {
          createAccountInput: { email, password, role },
        },
      })
    }
  }

  return (
    <div className="h-screen flex flex-col items-center justify-center ">
      <div className="w-full max-w-screen-sm flex flex-col px-5 items-center">
        <h4 className="w-full font-medium text-lleft text-3xl mb-5">
          Let's get started
        </h4>
        <form
          onSubmit={handleSubmit(onSubmit)}
          className="grid gap-3 mt-5 mb-5 w-full"
        >
          <input
            {...register('email', { required: 'Email is required' })}
            className="input"
            placeholder="email"
            type="email"
            required
          />
          {errors.email?.message && (
            <FormError errorMessage={errors.email?.message} />
          )}
          <input
            {...register('password', { required: 'Password is Required' })}
            className="input"
            placeholder="password"
            type="password"
            required
          />
          {errors.password?.message && (
            <FormError errorMessage={errors.password?.message} />
          )}
          
          ///select부분은 유심히 봐둔다.
          <select {...register('role', { required: true })} className="input">
            {Object.keys(UserRole).map((role, index) => (
              <option key={index}>{role}</option>
            ))}
          </select>
          <Button loading={loading} actionText="Create Account" />
         ********** {createAccountMutaionResult?.createAccount.error && (
            <FormError
              errorMessage={createAccountMutaionResult?.createAccount.error}
            />
          )}*********
          ///여기서 data:createAccountMutationResult임.
          ///onCompleted의 (data: CreateAccoountMutation) 와 헷갈리면 안됨.
        </form>
        <div className="text-lg">
          Already have an account?{''}
          <Link to="/" className="text-green-400 hover:underline">
            Log in now
          </Link>
        </div>
      </div>
    </div>
  )
}

export default CreateAccount
profile
코딩하는초딩쌤

0개의 댓글