나의 식당(myRestaurants) 페이지에서
식당 하나를 클릭했을때, 보여지는
식당 Detail Page
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 →
</Link>
///menu 등록 버튼.
<Link
className="mt-14 text-white hover:bg-green-600 bg-green-300 rounded-md py-3 px-10"
to={``}
>
Buy Promotion →
</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
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;
}
@Query(() => MyRestaurantOutput)
@Role(['Owner'])
findOneMyRestaurant(
@AuthUser() owner: User,
@Args('input') myRestaurantInput: MyRestaurantInput,
): Promise<MyRestaurantOutput> {
return this.restaurantService.findOneMyRestaurant(owner, myRestaurantInput);
}
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',
};
}
}
@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);
}
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를 다루도록 한다.