Restaurant Order Management Web App
Built with VueJS, Vuex, socket-io, and tailwindcss
Screenshots
Notifications
Order Detail
Take manual action on an order
Filtered order view
Restaurant Performance Take manual action on an order
Technology reasoning
- VueJS for reusable component design paradigm
- Vuex for a global state container (following flux architecture)
- socket-io to communicate real-time orders (vue-socket.io for it’s tight integration with vuex)
- tailwindcss to build a custom design system that isn’t the same as every other website on the internet (i.e. Bootstrap)
Steps to run project
1. Get Mapbox API key and add to .env file like so
In the .env file, replace YOUR_ACCESS_TOKEN
with your mapbox access token, which you can create for free at mapbox.com.
Order Detail view will not show a map view if you don’t have this setup.
VUE_APP_MAPBOX_ACCESS_TOKEN=YOUR_ACCESS_TOKEN
2. Install Dependencies
npm install
3. Run simulation
npm run simulation
Design Decisions
BE sends the following payload signature for each order:
{
destination: "801 Toyopa Dr, Pacific Palisades, CA 90272",
event_name: "CREATED",
id: "4b76edbf",
name: "Cheese pizza",
sent_at_second: 4
},
Orders are stored in a global state container, following flux design patterns, specifically using Vuex. I chose to use npm package vue-socket.io
to listen to socket-io events. I use vue-socket.io
to listen for new_event
emitted from socket-io at port 3000. SOCKET_new_event
mutation processes the event.
On the FE I store orders like so:
{
destination: "801 Toyopa Dr, Pacific Palisades, CA 90272",
event_name: "CREATED",
id: "4b76edbf",
name: "Cheese pizza",
sent_at_second: 4,
currentStatus: String, // new event status,
events: {
EVENT_NAME: { new_event_payload }
}
},
- Because there are only 5 possible
event_name
(CREATED
,COOKED
,DRIVER_RECEIVED
,DELIVERED
, andCANCELLED
), I chose to store each new event in anevents {}
(instead of in an array). This gives me instant O(1) access to whichever order event I’m looking for. For example, if I want to know when an event was delivered, in any component I can simply doorder.events.DELIVERED
directly in any component without having to lookup within an array of events. The one downside of this approach is we don’t keep a good log of all events in the order in which they are received. However, I do store asent_at_second
property when a user manually updates an order, so we could stitch together the order history in the correct order if such a request was made by Product & Design ? But at that point I would push for us to add a new api endpoint that fetches order history because we do not need the entire order history in most views.
Views
1. Home
- I built the home page as a dashboard with various modules that a restaurant owner would find most useful.
- Notifications show the user orders (and order updates) as they are being received in real-time. This view can get overwhelming so I added the option to filter to only new orders, and additionally the option to close the notifications side bar.
- The top row of filter options gives you a quick count of each filter and the number of items in that status currently. Clicking on any of these filters updates the orders you see right below.
- I also add 3 sections at the bottom of the dashboard:
- Best sellers: to see which ingredients are most popular
- it’s a simply word map count, I thought about pulling in a NLP library to categorize by food type (deserts, meals, and appetizers) or by culture (American, Italian, Middle Eastern) but time did not allow me to pursue this.
- Time to delivery
- a valuable metric for a restaurant owner is how long does it take for the restaurant to deliver items from the item of order. As a business owner he/she can help encourage their team/employees to track this value and improve over time.
- Average order value
- this seems like the most valuable information for the restaurant owner, but due to lack of $$$ data I just left this as a placeholder for future development.
- Best sellers: to see which ingredients are most popular
2. Order Review
- I started the entire project by building a dedicated
/orders/:id
page that can host information about any 1 order and can properly display all the relevant information. This page is routed to by clicking on a notification.
If I had more time!
- Update BE to send minimal payloads when order status changes, all we need on FE is the
id
andevent_name
on a new status order, or if the order item itself is being changed we could simply send{ id: ID, changes: { ... } }
. Right now we receive the entireorder
{}. - Add better animations when order statuses change
- Show full order history (see discussion above)
- Right now I assume most orders will transition between these 5 statuses: CREATED -> COOKED -> DRIVER_RECEIVED -> DELIVERED (with the option of it becoming CANCELLED at any point)
- Show in the dashboard at which point orders are being CANCELLED. If they’ve already been cooked or are en route, the restaurant is bleeding money, this is valuable information for restaurant owners to know.
- Add more thorough unit and e2e tests, specifically testing each component and various order status changes.
- Explore adding a FE state machine design pattern for each order.
- Use a NLP library to categorize food items by type of cuisine.
Tests
Run unit tests
npm run test:unit