My wife and I had been using Microsoft’s To Do to create our grocery lists and I was finding the experience to be a little lacking. I had never used To Do with other people and the more that we used it the more that we found we didn’t really enjoy using it for groceries.
My wife prefers to look through the history of completed items and add them back to the list whereas I blindly add items to the list without giving any thought as to what might have been completed in the past. This results in the list not being as clean as we would like. I’m stubborn, so I refused to search through the ‘done’ list every time I wanted to add something. It felt like we were both fighting the list.
I’d sum up my problems with To Do when used as a shopping list as the following:
- The search functionality is separate from adding an item to the list. I don’t want to search before adding something - the computer should do that for me!
- No way to ensure an item only showed up in the ‘done’ list once
- No suggestions based on how often something was added and completed
- Felt bloated and slow
To Do was cumbersome when it came to repeat (and incorrectly spelled) tasks
I looked at a few other grocery apps on our phones, but few seemed to meet an extra requirement of mine: the ability to access the list via the web. I really like being able to access the list through my computer instead of picking up my phone, so this is a must have.
Guess I’ll do it myself
With this in mind, I decided to make my own app focusing on the following functionality:
- Search for completed items that share the same name when adding an item to a list - allowing a previously added item to be seen as the user types
- Determine how many days it might be until an something is needed again by looking at how often it is added and removed from the list
- No duplicate items: if an item exists it can only be on the grocery list or the done list
- Accessible on any device that has a modern web browser
The last requirement was one of the largest determinants of how I was going to build this new project.
I wanted to make something with a simple mobile-first design
Keeping the backend on the Rails
When it came to the backend I settled on Rails. I admittedly wasn’t seeking high performance - I had been working with Rails for several months at work and realized that I had never built a Rails service from the ground up. I considered this to be a good opportunity to do so.
I really enjoy using ActiveRecord as an ORM and figured it would be easy to create a series of shared lists and items using a traditional SQL database. For the most part this was true and I managed to achieve what I wanted to with a few days of work.
For testing I used MiniTest for the first time. I usually use Rspec in the professional world, so I wanted to see how far I could get using Ruby’s built in testing framework. I definitely prefer Rspec to MiniTest, but MiniTest worked well in helping me create a service that functioned as I expected.
In the end, implementing the backend via Rails was painless and doesn’t leave me with a ton to say here. I’d consider that a success.
Supercharged React on the frontend
For the frontend I decided to check out the hype behind NextJS. I enjoy working in React and being able to get server-side rendering for free sounded great to my ears. In retrospect, I didn’t end up using the server-side rendering as much as I would have expected, but it’s nice to know that it’s there. NextJS also introduced me to the swr hooks (stale while revalidate) - these were really helpful and are used extensively to manage data.
I found working in NextJS to be pleasurable. There was a good amount of community support when it came to extra functionality:
- next-iron-session helped me manage the user’s login state so that I could access the JWT token provided by the Rails service on login to other endpoints that require it
- next-pwa was a great help in converting the app into a progressive web app, which let me turn the app into an APK for distribution on the Play Store, make it installable to phones’ home screens, and be used offline
As NextJS is built on React I was able to save time by taking advantage of several great libraries:
- react-bootstrap ports the classic Boostrap functionality to React components, making creating a slick looking app a breeze
- react-beautiful-dnd makes it easy to create drag and drop lists. When I’m making my shopping list I like to group by where things are in the store
- react-google-login lets you easily add a “Login with Google” button
React Bootstrap helped me build good looking components with minimal fuss
One of the main things that allowed me to easily make the app work when offline was the configurability provided by
next-pwa is built on top of Google’s Workbox libraries so the Workbox documentation is very helpful when going beyond what
next-pwa provides by default.
After increasing some of the cache sizes in the
pwa object of
next.config.js I was able to add a new matcher that would catch all api requests to my
item endpoint and update the caches returned for the various lists. It also saves the items that have been added and removed for the users’ lists in their localstorage so when the app detects that it is online again it syncs all of the changes with the server.
Doing the math
I ended up adding a feature that wasn’t planned in the original idea: the ability to get an estimate on how much your groceries will cost.
Estimates provided by an unnamed local grocer…
My original idea was to compare how much the groceries might cost by looking at several stores, giving an estimate for each one, and then the user could choose the cheapest store. I knew this could be really difficult to implement (especially beyond a Victoria, BC level), so once I found a store that had an easily accessible API I figured I’d just grab estimated costs from there.
I might return to the idea of comparing different grocery stores, but that could be really hard to scale. While I could throw something together to work for the stores around me, it’d be much more difficult to make something that would be aware of the grocery stores around any user and then provide a comparison between them!
Bagging it up
Someday I might open source what I’ve done with Bakalist, but there is definitely more work that needs to happen before then. For example: my tests on the Rails backend are currently broken, and I have no tests for the frontend!
I’m hoping that Google will accept this app on the Play Store - I’ve never had something on one of the app stores before so that will be an interesting experience. I’m currently in the process of submitting, so fingers crossed that I can get it approved.
Even if nobody other than me and my wife end up using Bakalist I’m pretty happy with how it has turned out. I’d definitely like to make the suggestion algorithm a bit smarter, since it’s pretty straightforward at this point, but that’s another tweak that can wait for another day.
Give it a try at http://bakalist.app