The 1-Day App Challenge
Published: 2023-09-21 16:12:50




In this article, I present a brief experiment where I created a web app to address my expense tracking challenge.

I share my app development journey, covering ideation, task planning, time tracking, technical decisions, and source code.
This article follows a process that can benefit junior developers and new graduates.

Additionally, it can spark discussions with seasoned developers, inviting them to share alternative problem-solving approaches.

‼️ SPOILER alert…it took more than one day 😅 ‼️



## Preface

**The problem**.
I initially tracked my expenses using Google Sheets.
Over time, data entry became cumbersome despite the spreadsheet's usefulness.

**The solution**.
That's when I discovered [Masareef](https://play.google.com/store/apps/details?id=com.appsqueue.masareef), an excellent Android app. I seamlessly transitioned my system from the spreadsheet to Masareef.

**The problem...again!**
However, upon switching to an iPhone, I found no iOS version available.
Other expense tracking apps I explored either lacked essential features or required subscriptions I wasn't willing to commit to.

**Back to the spreadsheet**.
Failing to find an adequate solution, I returned to using a spreadsheet.
To streamline data entry, I began daily tracking using Google Keep. At the end of the week, I transferred this data to the spreadsheet.
However, it was far from enjoyable, especially when I neglected to log expenses for over two weeks. At times, sorting through them took nearly an hour.

**Tailored solution**.
I decided to tackle this problem once and for all, by building my own app. Initially, I envisioned a simple form for entering expenses `(amount, category, wallet, and description)`, with the data saved directly to a Google Sheets spreadsheet using the Google Sheets API.

_I had a tight schedule with another project and limited time for this app, so I set myself a challenge to complete it in just one day._

**Idea 1**.
I explored the Google Sheets API documentation. While reading data from a spreadsheet was straightforward, writing to it required authentication, permissions, and the use of Google Cloud Platform (GCP), which would have exceeded the one-day timeframe.

**Idea 2**.
I considered creating a data converter from Google Keep to Google Sheets, a task I believed wouldn't be time-consuming. However, I realized that Google Keep wasn't the most efficient solution for simplifying data entry.

**Idea 3**.
I conceived a solution where I could prepare and format data within my app to match my spreadsheet structure, enabling simple copy-paste functionality into the spreadsheet for seamless tracking.

## Task Management
I streamlined the project by planning everything within a single Trello card, simplifying the process and avoiding unnecessary complexity on the Trello board.

| ![Trello card](https://i.imgur.com/zp7ea37.jpg) |
|-|
| *<center><small>Trello card of the tasks</small></center>* |

I used the description area for specifications and notes.
As the project took shape, I extracted tasks into multiple checklists categorized as Tasks, Later Improvements, Feedback, and Blog Post.
You can check the whole content of the card <a href="https://i.imgur.com/mBb39dA.jpg">here</a>.

## Time Tracking
I've been using [ToggleTrack](https://toggl.com/track/) for years, and in my opinion, it's the best tracking app. It combines simplicity with robust features and provides excellent reporting.


***Overall, this project took me 21 hours, 46 minutes and 48 seconds.***
If you think about it, it is not too far from the initial deadline I set for myself, especially if we disregard the additional updates I incorporated later. 😉

| ![Main workload report](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t1220wrd70xqen6q5wlc.png) | ![Additional update report](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0ccoccv1kocm13smtces.png) |
|----------|----------|
| *<center><small>Main work hours <small>(~18 hours)</small></small></center>* | *<center><small>Later updates <small>(~4 hours)</small></small></center>* |


## Technical stack
From the start, React was my primary choice, but I also wanted to explore some other tools that I hadn't had the opportunity to work with before. Here's my toolkit for this project.

- **React with TypeScript** for an interactive web app accessible on both web and mobile, ensuring a timely delivery.
- **[Vite](https://vitejs.dev/)** instead of create-react-app for a new technology experience.
- **Styling with [Tailwind CSS](https://tailwindcss.com/)**, I enjoyed using it in a previous project and wanted to explore it further.
- **[Zod](https://zod.dev/)** for powerful and straightforward validation.
- **[Firebase hosting](https://firebase.google.com/docs/hosting)** for deployment, which seamlessly integrates with GitHub actions for automatic deploys on push.
- **['pretty-ts-errors'](https://github.com/yoavbls/pretty-ts-errors)** Enhanced TypeScript error readability with this VS Code extension. ***(MUST HAVE)***
- **Testing**, while not initially necessary for the project's scope, I plan to implement testing using Jest and [React Testing Library](https://testing-library.com/docs/react-testing-library/intro/) in future iterations.
- **Source control**: I used Git in conjunction with the **Github Desktop** app, which provides improved code visualization before each commit.
- **Task management with [Trello](trello.com/)**, chosen for its simplicity and user-friendly interface over Jira."

### Data Storage
To meet my requirements for simplicity, minimal friction from a developer experience perspective, and avoiding the creation of a database or API endpoints due to project simplicity and time constraints, I chose **Firebase Real Time Database**.
  It's cost-effective for personal use, easy to set up, and aligns perfectly with my needs.
  Additionally, it offers built-in offline functionality when the page remains open.

### Data structure

#### Firebase
| ![Firebase db](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gp37qfhlul69kf68xnsu.jpg) |
|-|
|<center><small>*Data structure in Firebase DB*</small></center>|

In Firebase, I had an associative list of `/expense` that each had an autogenerated key and the following content for the value
```ts
{
    date: string,
    amount: string,
    wallet: string,
    subcategory: string,
    description: string
}
```

> _I used strings for the `amount` field to allow for the inclusion of expressions, such as `"=100+150+45"` within the content._

#### Spreadsheet
In the spreadsheet, the data is represented in columns `(date, amount, wallet, subcategory, description)`.
In the code, I utilized the following format, which will later be adapted for Google Sheets (<small>*See  "Export to Google Sheets" below*</small>).

- **Format**: `"date;amount;wallet;subcategory;description"`.
- **date**: `"dd-mm-yyyy"`.
- **amount**: value or expression (`500` | `'=40+120+75'`).
- **description**: comma separated strings, eg. `"milk, veggies, protein bars"`.

> _I refer to 'categories' for explanation purposes only. In the code, I use 'subcategories.' Categories do exist but are not visible in the current version._

## Look and Feel
Admitting my limited proficiency in creating UI from scratch, I opted to replicate the design of the Android app I had used. This decision saved valuable time, avoiding unnecessary design deliberations in the early stages. As a result, I implemented a straightforward, basic UI, with plans to refine it in the future.

I chose to streamline the app by having just two pages/components: one for the list of expenses and another for adding new expenses. 
Recognizing the frequent use of expense insertion, I set the 'Add Expense' component as the default view, with a convenient button for switching to the expense list.


| ![UI of the app](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e0iqxz3gtc0b78ycg648.jpg) |
|-|
| *<center><small>Super basic UI</small></small></center>* |

## Exporting the data
The final feature of the app is exporting data as a valid format for Google Sheets.
I found that the most practical export option from a UX perspective is to have the data copied to clipboard. This will allow me to directly paste the data into the spreadsheet and do some formatting there and voilà.
When pasting elements into Google Sheets, each line will be in a single cell.

![Data in a single cell](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/59pbykk3xqve1lnsdios.png)

To split the content of each cell into multiple columns, we use Google Sheets'  **Split text to columns** feature with semicolon (';') as a separator.
>_Note_: the semicolon should not be used in the content.

When exporting, items with identical **date, subcategory, and wallet** will be merged:
- Amounts will be summed.
- Descriptions will be concatenated.


**Example**:
The data format stored in Firebase Realtime Database.
```json
[{
   amount: "135", date:1693390995000, description:"coffee", 
   subcategory:"Groceries", wallet:"Groceries"
 },
  {
  amount:"210", date:1693390995000, description:"chicken", 
  subcategory:"Groceries", wallet:"Groceries"
}]
```

The data format exported from the app and passed to Google Sheets.
```
30-08-2023;=135+210;Groceries;Groceries;coffee, chicken
```

## Cleanup the Database

I've included a **Clear** button that allows me to remove all data once it's been exported to the spreadsheet. The spreadsheet serves as the single source of truth for my expenses, and the app primarily serves as a daily tracking tool.

## Updating the UI
After achieving a functional result that satisfied me, I made UI improvements by combining both components on a single page.
Now, data fetching happens on app load/reload instead of on page switches.
Additionally, when I insert an item, it instantly appears in the expenses list without the need for manual checking.

Here's the new UI.

| ![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/00gbhlb6rmozkibpjccs.png) |
|-|
| <center><small>_**UI update**: Both components on the same page_</small></center> |


## Conclusion
Creating solutions for your own problems can be the most fulfilling.
This approach reduced my session tracking time from potentially hours to just a couple of minutes.
It was also a valuable experiment to explore new tools like *Vite, Zod, and Firebase Hosting*. 
Additionally, I enhanced my knowledge of Markdown while preparing for this article.
_You can experiment with MD using this [website](https://stackedit.io) as well._


## Improvements
While the app is fully functional and meets my initial needs, there are areas that can be enhanced for a better user experience.
- Implementing searchable select elements would simplify subcategory selection when adding new expenses.
- Considering caching for lists of subcategories and wallets fetched from Google Sheets, which rarely change, could improve performance by reducing unnecessary fetches on app load.
- Enhancing the UI to match the quality of the app I initially copied. 

Although daily expense tracking has become easier, integrating a speech-to-text service may boost app productivity and increase effectiveness.

## After thoughts
- A week after completing the app, I continue to use Google Keep as backup due to an issue with Firebase DB where entries from my last session are occasionally lost. I haven't had the chance to debug this yet.
- Writing this article took me ***12 hours, 34 minutes and 48 seconds***!
_Almost as much time as it took me to write the app!!_
- While proof reading this article I found myself relying heavily on MS Edge's "Read Aloud" feature especially when listening at 2x speed.


Finally, here's the source code of [the repo](https://github.com/Abdelalim-dev/expense-tracker).