my-restaurant

김종민·2022년 9월 30일
0

Nuber-Client

목록 보기
12/21

나의 식당(myRestaurants) 페이지에서
식당 하나를 클릭했을때, 보여지는
식당 Detail Page


1. my-restaurant.tsx

import { gql, useQuery, useSubscription } from '@apollo/client'
import React, { useEffect } from 'react'
import { Link, useNavigate, useParams } from 'react-router-dom'
import { Dish } from '../../components/dish'
import {
  DISH_FRAGMENT,
  FULL_ORDER_FRAGMENT,
  RESTAURANT_FRAGMENT,
} from '../../fragments'
import {
  FindOneMyRestaurantQuery,
  FindOneMyRestaurantQueryVariables,
  PendingOrdersSubscription,
  PendingOrdersSubscriptionVariables,
} from '../../graphql/__generated__'

export const MY_RESTAURANT_QUERY = gql`
  query findOneMyRestaurant($input: MyRestaurantInput!) {
    findOneMyRestaurant(input: $input) {
      ok
      error
      restaurant {
        ...RestaurantParts
        menu {
          ...DishParts
        }
      }
    }
  }
  ${RESTAURANT_FRAGMENT}
  ${DISH_FRAGMENT}
`
///server의 myRestaurant Query 실행

const PENDING_ORDERS_SUBSCRIPTION = gql`
  subscription pendingOrders {
    pendingOrders {
      ...FullOrderParts
    }
  }
  ${FULL_ORDER_FRAGMENT}
`
///server에서 만든 subscription.
///order가 생성되면 order가 Owner의 해당restaurant 페이지에
///있으면, order를 실시간으로 받을 수 있음.

type IParams = {
  id: string
}

const MyRestaurant = () => {
  const { id } = useParams() as unknown as IParams
  ///path의 query(:id)로 날아오는 id를 useParams로 받음.
  ///type은 as unknow as IParams로~~ 매우중요!!!!
  
  const { data } = useQuery<
    FindOneMyRestaurantQuery,
    FindOneMyRestaurantQueryVariables
  >(MY_RESTAURANT_QUERY, {
    variables: {
      input: {
        id: +id,
      },
    },
  })
  ///findOneMyRestaurant Query실행하고 data받아옴.
  
  console.log(id)
  console.log(data)

  const { data: subscriptionData } = useSubscription<
    PendingOrdersSubscription,
    PendingOrdersSubscriptionVariables
  >(PENDING_ORDERS_SUBSCRIPTION)
  ///useSubscription을 사용해서 data를 실시간으로 받음.
  ///data가 중복되니 subscriptionData로 rename함.

  const navigate = useNavigate()
  ///restaurant에 order가 들어오면, order page로
  ///바로 이동할 수 있게 navigate사용 장착하기

  useEffect(() => {
    if (subscriptionData?.pendingOrders.id) {
      navigate(`/orders/${subscriptionData.pendingOrders.id}`)
    }
  }, [subscriptionData])
  ///subscriptionData가 있을 경우 order page로 
  ///redirect 시켜줌!!

  return (
    <div>
      <div
        className=" py-28 bg-cover"
        style={{
          backgroundImage: `url(${data?.findOneMyRestaurant.restaurant?.coverImg})`,
        }}
      >
      ///식당 화면 layout!!
        <div className="bg-white w-1/2 py-8 opacity-60 ">
          <h4 className="text-4xl mb-3">
            {data?.findOneMyRestaurant.restaurant?.name}
          </h4>
          <h5 className="test-sm font-light mb-2">
            {data?.findOneMyRestaurant.restaurant?.category?.name}
          </h5>
          <h6 className="test-sm font-light">
            {data?.findOneMyRestaurant.restaurant?.address}
          </h6>
        </div>
      </div>
      <div className="mt-10 ml-4">
        <Link
          className="mr-14 hover:bg-gray-600 text-white rounded-md bg-gray-300 py-3 px-10"
          to={`/restaurants/${id}/add-dish`}
        >
          Add Dish &rarr;
        </Link>
        ///menu 등록 버튼.
        
        <Link
          className="mt-14 text-white hover:bg-green-600 bg-green-300 rounded-md py-3 px-10"
          to={``}
        >
          Buy Promotion &rarr;
        </Link>
      </div>
      <div className="mt-10">
        {data?.findOneMyRestaurant.restaurant?.menu.length === 0 ? (
          <h3>You have no dish</h3>
        ) : (
          <div className="grid mt-16 md:grid-cols-3 gap-x-5 gap-y-10 mx-5 mb-5">
            {data?.findOneMyRestaurant.restaurant?.menu.map((dish, index) => (
              <Dish
                key={index}
                name={dish.name}
                description={dish.description}
                price={dish.price}
              />
              ///menu 나열..
              ///Dish Component는 다다음 POST에서
              ///다룰 예정입니다.
            ))}
          </div>
        )}
      </div>
    </div>
  )
}

export default MyRestaurant

2. my-restaurant.dto.ts(server)

import { Field, InputType, ObjectType, PickType } from '@nestjs/graphql';
import { MutationOutput } from 'src/common/dtos/output.dto';
import { Restaurant } from '../entities/restaurant.entity';

@InputType()
export class MyRestaurantInput extends PickType(Restaurant, ['id']) {}

@ObjectType()
export class MyRestaurantOutput extends MutationOutput {
  @Field(() => Restaurant)
  restaurant?: Restaurant;
}

3. findOneMyRestaurant.resolver.ts

  @Query(() => MyRestaurantOutput)
  @Role(['Owner'])
  findOneMyRestaurant(
    @AuthUser() owner: User,
    @Args('input') myRestaurantInput: MyRestaurantInput,
  ): Promise<MyRestaurantOutput> {
    return this.restaurantService.findOneMyRestaurant(owner, myRestaurantInput);
  }

4. findOneMyRestaurant.service.ts

  async findOneMyRestaurant(
    owner: User,
    { id }: MyRestaurantInput,
  ): Promise<MyRestaurantOutput> {
    try {
      const restaurant = await this.restaurants.findOne({
        //relations: ['menu', 'order'],
        where: {
          id,
          owner: {
            id: owner.id,
          },
        },
      });
      console.log(restaurant);
      return {
        restaurant,
        ok: true,
      };
    } catch (e) {
      return {
        ok: false,
        error: 'could not found restaurant',
      };
    }
  }

4. subscription부분(orders.resolver.ts)

  @Subscription(() => Order, {
    filter: ({ pendingOrders: { ownerId } }, _, { user }) => {
      console.log(ownerId, user.id);
      return ownerId === user.id;
    },
    resolve: ({ pendingOrders: { order } }) => order,
  })
  @Role(['Owner'])
  pendingOrders() {
    return this.pubSub.asyncIterator(NEW_PENDING_ORDER);
  }

5. trigger 부분.(order.service/createOrder)

 async createOrder(
    customer: User,
    { restaurantId, items }: CreateOrderInput,
  ): Promise<CreateOrderOutput> {
    try {
      const restaurant = await this.restaurants.findOne({
        where: {
          id: restaurantId,
        },
      });
      if (!restaurant) {
        return {
          ok: false,
          error: 'Restaurant not found',
        };
      }
      let orderFinalPrice = 0;
      const orderItems: OrderItem[] = [];
      for (const item of items) {
        const dish = await this.dishes.findOne({
          where: {
            id: item.dishId,
          },
        });
        console.log(`Dish Price:${dish.price}`);
        console.log(dish);
        if (!dish) {
          return {
            ok: false,
            error: 'Dish not found',
          };
        }
        let dishFinalPrice = dish.price;
        for (const itemOption of item.options) {
          const dishOption = dish.options.find(
            (dishOption) => dishOption.name === itemOption.name,
          );

          if (dishOption) {
            if (dishOption.extra) {
              dishFinalPrice = dishFinalPrice + dishOption.extra;
            } else {
              const dishOptionChoice = dishOption.choices?.find(
                (optionChoice) => optionChoice.name === itemOption.choice,
              );
              if (dishOptionChoice) {
                if (dishOptionChoice.extra) {
                  dishFinalPrice = dishFinalPrice + dishOptionChoice.extra;
                }
              }
            }
            // if (dishOption) {
            //   if (dishOption.extra) {
            //     dishFinalPrice = dishFinalPrice + dishOption.extra;
            //   }
            // }
          }
        }
        console.log('dishFinalPrice', dishFinalPrice);

        orderFinalPrice = orderFinalPrice + dishFinalPrice;
        const orederItem = await this.orderItems.save(
          this.orderItems.create({
            dish,
            options: item.options,
          }),
        );
        orderItems.push(orederItem);
        console.log('OrderFinalPrice', orderFinalPrice);
      }

      const order = await this.orders.save(
        this.orders.create({
          customer,
          restaurant,
          total: orderFinalPrice,
          items: orderItems,
        }),
      );
      console.log(order);
      
      ----------------trigger부분--------------------------
      await this.pubSub.publish(NEW_PENDING_ORDER, {
        pendingOrders: { order, ownerId: restaurant.ownerId },
      });
     -----------------------------------------------------
      return {
        ok: true,
        orderId: order.id,
      };
    } catch {
      return {
        ok: false,
        error: 'Could not create Order.',
      };
    }
  }

NOTICE!!!
나의 식당들 중 하나를 클릭했을떄,
하나의 식당을 자세히 볼수 있고,
Order가 들어왔을때, subscription으로 실시간으로
oder페이지로 이동하게 한다.

다음 POST에서 add-dish, create-restaurant를 다루도록 한다.

profile
코딩하는초딩쌤

0개의 댓글