Bringing life to my UI with fullstack engineering
How pulse checks and crowdsourcing help employees smile @ work.
In my Human-Computer Interaction Design class, I led the development of a React Native app that helps teams adjust culture through daily steps.
In my project team's needfinding, we found that employees wanted a communal way to gauge the current mood of their team and concrete ways to adjust it. With Smile@Work, we solved this need with an app that lets teams conduct mood pulse checks, see the majority team mood, and crowdsource action items for the team to implement.
Creating a clean, friendly UI:
The most difficult design choice I directed my team on was how to keep our app professional for the workplace, but fun enough to be inviting.
I led the final iteration of our design system, creating a set of vibrant colors, designing minimalist illustrations, and implementing a modern typeface.
We cared deeply about designing a clean UI that would show employees all desired information with a quick glance. For busy employees, having another tedious UI flow to learn would not effectively solve the user need.
The UI copy is short and action-oriented, and we effectively organize the most high-priority information for users on the homepage.
Developing a seamless, informative app:
The most exciting component I implemented was the changing accent colors that update to reflect the current majority team mood. This feature gets to the core of Smile@Work: by first helping teams gauge the mood every day, we can then help them take the best next steps.
The most nuanced component I implemented was the selectively hidden navbar. We wanted to subtly emphasize the required nature of the morning pulse check, without overwhelming users with complex instructions.
On the backend, to have a running feed of Thoughts and likes, I connected our app with a Firebase database.
Zap! Bang! Pop!
What is all
As a full-stack engineering intern at Expo, I directed the product development of a new Activity dashboard.
Users lacked an efficient way to view all updates to their Expo project at one time. Activity streamlines all of these core updates, maintaining a powerful developer experience. Especially as Expo grows.
I led a team of backend engineers, frontend designers, and User Analytic managers to successfully launch the dashboard on production in just 6 weeks.
Designing a strong feature:
Given the cross-functional nature of my team, I decided to design high-fidelity UI mockups early-on.
They made communicating my vision and keeping everyone on the same page a seamless process.
Because I knew I would also be building this UI, I learned to take extra care to design for edge cases (anonymous builds, no activity to show).
Creating a flexible frontend:
Bringing together multiple types of objects into one, coherent design can be tricky.
I became a better developer by building an extremely flexible UI. One that would work for app store builds, OTA updates, team member changes, and any future features.
My solution was creating a highly-structured, customizable React component. The base structure of any update is the same— icon, attribution, and details container.
And with just a few new cases in switch statements, any Expo developer can then customize the contents of that base structure to render any update type in a way that users will recognize.
Building a maintainable backend:
Because Expo stores project data in multiple databases, it was crucial to strategize with Senior Engineers on how to efficiently pull and paginate all the data we needed.
Through testing, we discovered that conventional methods of pagination would be insufficient, and collaborated to build a custom solution.
I developed PostgreSQL offsets using timestamps to query for the new data, and created a new GraphQL API interface with the optimized queries.
The most exciting aspect of this backend work is its consideration for future Expo operations. There will certainly be new Expo update types to add, each with unique data fields.
Excitingly though, this API efficiently handles any combination of types because it presumes no fixed structure. It depends only on leveraging the timestamp that every update occurred at. Creating such maintainable code improved how I develop.