Pablo
Workplace emergency tracking system + dashboard.

Product Brief
Meet "Pablo" - it's a system built to boost safety at the workplace. Think of solar workers who might be in tricky situations. They could fall, faint, or even breathe in harmful gases. Every moment counts. That's where Pablo comes in. It uses radios to check if someone stops moving or seems unconscious, and then it kicks off an alarm. If there's no response, this info is sent to a server and shows up on the main dashboard. This means quick help can be on the way. There was a first version, but it needed an update. My task? Redesign and make the frontend for this new v2 app.
Main Challenges
I had to design and code on my own
When it came to design and frontend I was basically alone. I was an all-in-one dev team. The first app wasn't great in looks or user-friendliness, and it used different technologies. I had nothing to base on. Essentially, I was venturing into uncharted territory with just 3 months to produce a top-tier, ready-for-business app starting from scratch.Technical Stuff, User-Friendly Goal
The topic was pretty techy. Still, the app had to be easy for everyone to use. I had to work with my buddy who was responsible for the tech and backend integrations (shout out to @simnkurek).To get things right, I had to learn about how radios function, the protocols, and more, all while keeping in mind what users would want from the app.Deep dive into new technologies
Right from the start, a simple 2D map wasn't going to cut it. Too much info and not enough space. At first, I thought of an isometric view, but ended up going with a 3D map. This meant I had to use three.js a library I'd only touched briefly before. I had to learn and understand three.js, react-fabric and react-three-drei on the go, during the development process.You won't achieve anything without a good plan
As said in the header - you won't achieve anything without a good plan. Due to limited time there was no time for mistakes and rewrites. The whole app had to be thoroughly planned even before the initial UI design stage even started. To achieve it I had to spend numerous hours planning the app on Miro and consulting the layout with our client and my backend developer. This approach proved to be the stepping stone that allowed me to create this app in such a short time period. It provided a robust structure a source of truth that always could be referenced and built upon.

Design phase
To speed up the process as much as possible, I had to create a design system as fast as possible. Usually, I take some time, prepping a couple of the most important/distinct screens and then creating a system that will fit all of them and make them stand out. Here it wouldn't cut it. I basically prepared the main screen and one utility screen and it was it. I didn't have time to explore. Instead, I leaned heavily on my gut feeling and past experiences, building out the entire system from just those two screens. It was definitely a tightrope walk, but on the flip side, it was a massive time-saver.




Map
During our exploration, it became clear that the old 2D map was just... lacking. Overlapping buildings? Confusing radio placements? Yep, it had those issues. And let's not even talk about how tricky it was to gauge space when you're juggling tens of radios on the same flat plane. It was usually based on a screenshot grabbed from a map app or a building layout. Sounds efficient, right? Wrong. This method meant dumping a lot of unnecessary info onto the operator. My goal was to simplify this view to the point that even a newbie could dive in and feel like a pro in no time. No BS, just the things they need. I've opted for custom SVG maps tailored to each client. And here's the cool part, with just a little sprinkle of three.js magic I would be able to create an immersive 3D experience from these color-coded SVGs. Not only is this super functional, but let's be real—it looks absolutely epic.

Simplicity
As I've already mentioned, my goal was to simplify the app. Previously, everything revolved around one screen, overstuffed with menus, sometimes leaving even the veterans scratching their heads. So, I had an idea: why not tailor the app to specific roles? If you're in charge of overseeing radiophones and managing emergencies, there's no need for you to dive into map editing, logs, or group editing. Segmenting the app into four role-specific suites allowed me to trim down the core version to just a handful of screens (3-7 based on how you define a screen) while the whole app has well over 30 pages. A neat, tailored experience for everyone!

This also meant splitting complex actions into manageable slices.
Profile Creation

Alarm Handling

Development
Now the fun part began. With just two months on the clock to code the designed pages, there was zero room for do-overs. I knew that I had to do things right the first time. Major overhauls? Nope. At best, I had wiggle room for minor tweaks.
To avoid being stuck for prolonged periods due to mishaps, I decided to stick to technologies I was already well-versed in, eliminating the constant need to reference documentation. Sure, I made an exception with three.js (admittedly, I was still wrapping my head around it). But that one leap into unfamiliar territory made me even more resolute to stick with familiar shores elsewhere—like opting for SCSS modules over Tailwind I'd been dabbling in, or choosing Redux Toolkit over Zustand. Familiarity was my safety net, ensuring I stayed on track and on time.
Solid setup
As with the map plan that allowed me to accelerate my design process. A good setup is the must-have thing when you want to develop in a fast-phased manner. Next.js was a lifesaver, taking on the brunt of the tedious webpack configuration. Apart from a simple svgr config, I was spared from diving into the webpack config file. The next step (pun intended) was setting up .eslint and prettier. Since I've started using eslint on save I cannot imagine coding without this neat tool keeping my files clean and saving time on manually formatting files. Over the years, I've crafted some robust eslint configs that fit my coding style, so setting this up was essentially a copy-paste. This, coupled with a streamlined structure, barrel exports, ts aliases, and husky scripts on commit, allowed me to effortlessly code and commit, without getting bogged down by the intricacies of the environment.
Map
Starting with three.js was a journey from scratch, as I knew little about it. Crafting this page posed quite the challenge, but it also emerged as the most intriguing aspect of this project. It was a fun change from the usual routine of making form/table pages: get data, show it, and update it. Doing the same thing over and over can get dull. My goal was creating the map was to use color-coded SVGs and transform them into 3D objects. As it turned out three.js has a built-in methods to transform svgs into objects. With a bit of clever finessing, I achieved exactly what I was aiming for.


This didn't mean I was done tho. There was still a laundry list of tasks to tackle, like displaying radios with their respective labels. This seemingly straightforward task turned out to be a major pain point. In react-three-fiber, each HTML element within the canvas is treated as its own separate React root. So, what's the big deal? I intended for these labels to navigate throughout the app, utilizing router context. However, contexts aren't shared between different React roots, which, when you think about it, does make sense. My breakthrough came when I stumbled upon context-bridging. It was the lifeline I didn't know I needed!
Map Editor
While I successfully got the map up and running, manipulating building data remained a hurdle. I was stuck manually inputting height, label, and floor information. To streamline this process, I integrated the map editor into the app. It allowed me to repurpose elements like the canvas, breadcrumb system, 2D floor plan system, and beacons. This alone saved me a significant amount of time. To further enhance the user experience, I implemented a local storage system combined with timestamps. This ensured that users wouldn't lose their progress due to unforeseen issues like internet outages or system crashes.


Final stages
After a tiresome 2,5 months of planning, designing and coding it was time to test it in a real-life scenario. Previously I had to rely on backend-mocked data because the localization system was WIP for the most of my development phase. It was finally time to test it. We met in person, ordered a box o large pizza and started integrating our systems. Surprisingly we didn't have to wait for long, it worked perfectly on the second try. The following weeks were dedicated to thorough testing, ironing out bugs, and putting the finishing touches on the app.
Wrapping up
Reflecting on this journey with "Pablo", it's evident that this project was much more than just another development task. It was an intense learning curve, a dive into uncharted waters, and most importantly, a testament to the power of resilience and adaptability. I grappled with new technologies, surmounted unexpected challenges, and at times, relied heavily on intuition and experience. The blend of design, technology, and user-centric thinking was invigorating. This project taught me the importance of thorough planning, the value of a well-thought-out design system, and the significance of staying grounded in familiar territory when timelines are tight. But beyond the technicalities, I've gained a deeper appreciation for the intricate dance between functionality and user experience. Every hurdle, every late night, and every slice of pizza during those integration sessions enriched my perspective as a developer. And as I move forward, I carry with me the invaluable lessons from "Pablo" - a true masterclass in growth, grit, and the art of creating impactful solutions.
Let's connect
Got a project in mind? Let's connect and create something epic together!
hello@morte.work