Driver Dashboard의 마지막 부분.
Order가 들어오고
Owner가 status를 cooked를 했다면, Driver에게
Order가 push로 가고,
Driver가 status를 PickedUp, Deliverd라고
바꿔줄 수 있다.
또한, Client의 위치가 구글맵에 찍히게 해 본다.
챌린지로~
import React, { useEffect, useState } from 'react'
import GoogleMapReact from 'google-map-react'
import { gql, useMutation, useSubscription } from '@apollo/client'
import { FULL_ORDER_FRAGMENT } from '../../fragments'
import {
CookedOrdersSubscription,
TakeOrderMutation,
TakeOrderMutationVariables,
} from '../../graphql/__generated__'
import { Link, useNavigate } from 'react-router-dom'
const COOCKED_ORDERS_SUBSCRIPTION = gql`
subscription coockedOrders {
cookedOrders {
...FullOrderParts
}
}
${FULL_ORDER_FRAGMENT}
`
///coockedOrders subscription을 server로부터 불러온다.
///아래의 server쪽 code 참조할 것.
const TAKE_ORDER_MUTATION = gql`
mutation takeOrder($input: TakeOrderInput!) {
takeOrder(input: $input) {
ok
error
}
}
`
///takeOrder mutation
///driver가 takeOrder할 예정.
interface ICoords {
lat: number
lng: number
}
interface IDriverProps {
lat: number
lng: number
$hover?: any
}
const Driver: React.FC<IDriverProps> = () => <div className="text-lg">🚚</div>
export const Dashboard = () => {
const [driverCoords, setDriverCoords] = useState<ICoords>({ lat: 0, lng: 0 })
const [map, setMap] = useState<google.maps.Map>()
const [maps, setMaps] = useState<any>()
const onSuccess = ({
coords: { latitude, longitude },
}: GeolocationPosition) => {
setDriverCoords({ lat: latitude, lng: longitude })
}
const onError = (error: GeolocationPositionError) => {
console.log(error)
}
useEffect(() => {
navigator.geolocation.watchPosition(onSuccess, onError, {
enableHighAccuracy: true,
})
}, [])
useEffect(() => {
if (map && maps) {
map.panTo(new google.maps.LatLng(driverCoords.lat, driverCoords.lng))
const geocoder = new google.maps.Geocoder()
geocoder.geocode(
{
location: new google.maps.LatLng(driverCoords.lat, driverCoords.lng),
},
(result, status) => {
console.log(result, status)
}
)
}
}, [driverCoords.lat, driverCoords.lng])
const onApiLoaded = ({ map, maps }: { map: any; maps: any }) => {
map.panTo(new google.maps.LatLng(driverCoords.lat, driverCoords.lng))
setMap(map)
setMaps(maps)
}
const makeRoute = () => {
if (map) {
const directionsService = new google.maps.DirectionsService()
const directionsRenderer = new google.maps.DirectionsRenderer()
directionsRenderer.setMap(map)
directionsService.route(
{
origin: {
location: new google.maps.LatLng(
driverCoords.lat,
driverCoords.lng
),
},
destination: {
location: new google.maps.LatLng(
driverCoords.lat + 0.01,
driverCoords.lng + 0.01
),
},
travelMode: google.maps.TravelMode.TRANSIT,
},
(result, status) => {
directionsRenderer.setDirections(result)
}
)
}
}
const { data: coockedOrdersData } = useSubscription<CookedOrdersSubscription>(
COOCKED_ORDERS_SUBSCRIPTION
)
///subscription Data가 있으면,
///makeRoute 함수를 실행해서, 구글지도에 길을 그려줌.
useEffect(() => {
if (coockedOrdersData?.cookedOrders.id) {
makeRoute()
}
}, [coockedOrdersData])
///takeOrder가 실행되면, order page로 이동시켜줌.
const navigate = useNavigate()
const onCompleted = (data: TakeOrderMutation) => {
if (data.takeOrder.ok) {
navigate(`/orders/${coockedOrdersData?.cookedOrders.id}`)
}
}
///takeOrder mutation을 실행했을때,
const [takeOrderMutation] = useMutation<
TakeOrderMutation,
TakeOrderMutationVariables
>(TAKE_ORDER_MUTATION, { onCompleted })
///아래부분의 return()의 accept Challenge버튼을 눌렸을떄,
///아래 accept Chanllenge에서 ///coockedOrdersData?.cookedOrders.id를 받아와서
///orderId로 받아서, takeOrderMutation의
///variables에 넣어서 takeOrderMutaiton을 실행시켜줌.
const triggerMutation = (orderId: number) => {
takeOrderMutation({
variables: {
input: {
id: orderId,
},
},
})
}
return (
<div>
<div style={{ height: '70vh', width: '100%' }}>
<GoogleMapReact
yesIWantToUseGoogleMapApiInternals
onGoogleApiLoaded={onApiLoaded}
bootstrapURLKeys={{ key: 'AIzaSyCQBuKy-bkomVZm4BTMYc30cCDvtCpateI' }}
defaultCenter={{
lat: 35.166535,
lng: 126.9779692,
}}
defaultZoom={15}
>
<Driver lat={driverCoords.lat} lng={driverCoords.lng} />
</GoogleMapReact>
</div>
<div className="max-w-screen-sm mx-auto bg-white relative -top-10 shadow-lg py-8 px-5">
{coockedOrdersData?.cookedOrders.restaurant ? (
<>
<h1 className="text-center text-3xl font-medium">
New Coocked Order
</h1>
<h4 className="text-center text-2xl font-medium">
Pick it up soon! @{' '}
{coockedOrdersData?.cookedOrders?.restaurant?.name}
</h4>
<button
onClick={() =>
triggerMutation(coockedOrdersData?.cookedOrders.id)
}
className="btn w-full text-center mt-5 block"
>
Accept Challenge
</button>
///Accept Challenge버튼을 누르면, takeOrder
///mutation이 실행되게 함.
</>
) : (
<h1 className="text-center text-3xl font-medium">No Orders Yet</h1>
)}
</div>
</div>
)
}
!!!cookedOrdes Subscription(orders.resolvers.ts)
@Subscription(() => Order)
@Role(['Delivery'])
cookedOrders() {
return this.pubSub.asyncIterator(NEW_COOKED_ORDER);
}
!!!editOrder(orders.service.ts)
async editOrder(
user: User,
{ id: orderId, status }: EditOrderInput,
): Promise<EditOrderOutput> {
try {
const order = await this.orders.findOne({
where: {
id: orderId,
},
});
if (!order) {
return {
ok: false,
error: 'Order not found',
};
}
if (!this.canSeeOrder(user, order)) {
return {
ok: false,
error: 'Can not see this',
};
}
let canEdit = true;
if (user.role === UserRole.Client) {
canEdit = false;
}
if (user.role === UserRole.Owner) {
if (status !== OrderStatus.Cooking && status !== OrderStatus.Cooked) {
canEdit = false;
}
}
if (user.role === UserRole.Delivery) {
if (
status !== OrderStatus.PickedUp &&
status !== OrderStatus.Deliverd
) {
canEdit = false;
}
}
if (!canEdit) {
return {
ok: false,
error: 'You can not do that',
};
}
await this.orders.save({
id: orderId,
status,
});
const newOrder = { ...order, status };
if (user.role === UserRole.Owner) {
if (status === OrderStatus.Cooked) {
await this.pubSub.publish(NEW_COOKED_ORDER, {
cookedOrders: newOrder,
});
}
}
await this.pubSub.publish(NEW_ORDER_UPDATE, {
orderUpdates: newOrder,
});
return {
ok: true,
};
} catch {
return {
ok: false,
error: 'Could not edit order',
};
}
}
!!!!takeOrder(orders.service.ts)
async takeOrder(
driver: User,
{ id: orderId }: TakeOrderInput,
): Promise<TakeOrderOutput> {
try {
const order = await this.orders.findOne({
where: {
id: orderId,
},
});
if (!order) {
return {
ok: false,
error: 'Order not found',
};
}
if (order.driver) {
///order에 driver가 있으면,
return {
ok: false,
error: 'This order already has a driver',
};
}
await this.orders.save({
id: orderId,
driver,
});
await this.pubSub.publish(NEW_ORDER_UPDATE, {
orderUpdates: { ...order, driver },
});
return {
ok: true,
};
} catch {
return {
ok: false,
error: 'Could not update order',
};
}
}
}
!!!NOTICE
이것으로 driver Dashboard는 마무리.
challenge는 꼭 도전해본다.
주소를 입력받아 좌표로 바꾸고 지도에 찍어보는것!!