addDish(input dish)

김종민·2022년 10월 4일
0

Nuber-Client

목록 보기
14/21

들어가기
Owner의 restaurant page에서 식당의 menu를
추가하는 page 및 component
menu의 option받는거 떄문에 복잡해짐.
집중할것!!


1. src/pages/owner/add-dish.tsx


import { gql, useMutation } from '@apollo/client'
import React, { useState } from 'react'
import { useForm } from 'react-hook-form'
import { useNavigate, useParams } from 'react-router-dom'
import Button from '../../components/button'
import {
  CreateDishMutation,
  CreateDishMutationVariables,
} from '../../graphql/__generated__'
import { MY_RESTAURANT_QUERY } from './my-restaurant'

const CREATE_DISH_MUTATION = gql`
  mutation createDish($input: CreateDishInput!) {
    createDish(input: $input) {
      ok
      error
    }
  }
`
///server의 createDish API를 호출함..

interface IParams {
  restaurantId: string
}
///createDish의 input의 type을 설정해줌.

interface IForm {
  name: string
  price: string
  description: string
  [key: string]: string //그외 싸그라니
}
///createDish의 variables들의 type을 설정해줌.
///option부분은 [key:string]로 해줌.

const AddDish = () => {
  const { restaurantId } = useParams() as unknown as IParams
  ///path가  path: '/restaurants/:restaurantId/add-dish'
  ///임으로 restaurnatId를 useParam를 이용해서 받아옴.
  
  const navigate = useNavigate()
  const [createDishMutation, { loading }] = useMutation<
    CreateDishMutation,
    CreateDishMutationVariables
  >(CREATE_DISH_MUTATION, {
    refetchQueries: [
      {
        query: MY_RESTAURANT_QUERY,
        variables: {
          input: {
            id: +restaurantId,
          },
        },
      },
    ],
  })
  ///createDish mutation을 실행 후, my restaurantDetail 
  ///page를 refetch해줌.
  ///만들어진 menu가 화면에 바로 나타날 수 있게~

  const { register, handleSubmit, getValues, setValue } = useForm<IForm>({
    mode: 'onChange',
  })
	///react-hook-form!!!

  const onSubmit = () => {
    const { name, price, description, ...rest } = getValues()
    ///option부분은 ...rest로 받음.
    
    console.log(rest)
    ///rest를 찍어보면 무엇이 나오는지 알 수 있음.
    
    const optionsObject = optionsNumber.map((id) => ({
      name: rest[`${id}-optionName`],
      extra: +rest[`${id}-optionExtra`],
    }))
    ///option부분은 optionsObject로 만들어줌.
    ///반드시 console을 찍어서 모양을 확인할 것.
    
    console.log(optionsObject)
    
    ///createDishMutation에 variables들을 넣어줌.
    ///options 부분은 optionsObject를 만들어서 넣어줌.
    ///restaurantId는 usePaprams로 따옴.
    createDishMutation({
      variables: {
        input: {
          name,
          price: +price,
          description,
          restaurantId: +restaurantId,
          options: optionsObject,
        },
      },
    })
    navigate(-1) 
    ///createDish후 page를 myRestaurant page로 되돌려놓음
    ///생성항 dish확인 가능함
  }
  
  ///여기서 부터 엄청중요...
  ///dish생성방법.
  ///options의 갯수를 배열(숫자로 된)로 지정해서 useState로 만든다.
  ///default값은 빈배열로!!
  const [optionsNumber, setOptionsNumber] = useState<number[]>([])
  
  
  const onAddOptionClick = () => {
    setOptionsNumber((current) => [Date.now(), ...current])
  }
  ///option 추가 버튼을 누를경우, 실행되는 함수.
  ///현재의 배열에 Date.now()을 숫자로 된 것이
  ///배열에 추가된다.
  
  const onDeleteClick = (idToDelete: number) => {
    setOptionsNumber((currnet) => currnet.filter((id) => id !== idToDelete))
    setValue(`${idToDelete}-optionName`, '')
    setValue(`${idToDelete}-optionExtra`, '')
  }
  ///추가할려던 option을 제거하는 함수.
  ///옵션Delete를 클릭했을때, 클릭한 option의 id를 idToDelete로
  ///받아와서 setOptionsNumber에 들어있는 option들 중, 
  ///id가 다른것은 없애는 작업.
  ///setValue부분은 delete한 option의 값을 비워준다.
  
  return (
    <div className="max-w-screen-sm mx-auto flex flex-col items-center mt-52">
      <h4 className="font-semibold text-2xl mb-3">음식 추가</h4>
      <form
        onSubmit={handleSubmit(onSubmit)}
        className="grid gap-3 mt-3 mb-5 w-full"
      >
        <input
          {...register('name', {
            required: 'name is required',
            maxLength: { value: 30, message: 'max char is 30' },
          })}
          required
          maxLength={30}
          placeholder="name"
          className="input"
        />
        ///menu name input react-hook-form

        <input
          {...register('price', { required: 'price is required' })}
          name="price"
          placeholder="price"
          className="input"
          type="number"
          min={0}
        />
        ///menu price input react-hook-form
        
        <input
          {...register('description', { required: 'description is required' })}
          name="description"
          placeholder="description"
          className="input"
          type="text"
        />
        ///menu description input react-hook-form
        
        <div className="my-10">
          <h4 className="font-medium mb-3 text-lg">음식 추가 옵션</h4>
          <span
            className="cursor-pointer text-white bg-gray-400 hover:bg-gray-600 py-1 px-2 mt-5 rounded-md"
            onClick={onAddOptionClick}
          >
          ///위에서 만든 option 추가 버튼
          ///optionsNumber가 추가됨.
            Add Option
          </span>
          
          ///위에서 useState로 만든 optionsNumer를 
          ///map으로 뿌려줌.
          {optionsNumber.length !== 0 &&
            optionsNumber.map((id) => (
              <div key={id} className="mt-5">
                <input
                  {...register(`${id}-optionName`)}
                  className="ml-5 py-2 px-4 focus:outline-none mr-3 focus:border-gray-600 border-2"
                  placeholder="Option Name"
                  type="text"
                />
                ///option의 name을 입력하는 부분.
                ///register되는 name을 집중해서 봐둘것.
                ///`${id}-optionName`으로 option name이
                ///설정됨.
                
                <input
                  {...register(`${id}-optionExtra`)}
                  className="ml-5 py-2 px-4 focus:outline-none focus:border-gray-600 border-2"
                  placeholder="Option Extra"
                  min={0}
                  type="number"
                  defaultValue={0}
                />
                ///option의 extra가 입력하는 부분.
                ///register되는 name을 집중해서 봐둘것.
                ///`${id}-optionExtra`으로 option name이
                ///설정됨.
                ///extra이기 떄문에 defaultValue는 0으로
                ///설정함.
                
                <span
                  className="cursor-pointer ml-3 text-white bg-red-400 hover:bg-red-600 py-1 px-2 mt-5 rounded-md"
                  onClick={() => onDeleteClick(id)}
                >
                  Delete Option
                </span>
                ///option옆의 Delete 버튼을 누르면, option이 
                ///사라지게 하는 버튼.
                ///클릭시 그 옵션의 id를 담아서
                ///onDeleteClick 함수로(id => idToDelete)
                ///보낸다.
                ///id를 담아서 보낼때에는 ()=> 의
                ///함수 형식을 취한다.
                
              </div>
            ))}
        </div>
        <Button loading={loading} actionText="Make Dish" />
      </form>
    </div>
  )
}

export default AddDish 

  

매우 어려운부분 ㅠㅠㅠ
마르고 닳도록 볼것!!

profile
코딩하는초딩쌤

0개의 댓글