Crushing 14 Features in One Session: From Phone Formatting to Payment Processing
Just wrapped up what might be one of my most productive dev sessions yet. Knocked out 14 different features and fixes across both SnowTrack and LawnTrack in a single sitting. Sometimes you just get in the zone, you know?
The Big Wins
Started with what seemed like simple phone number formatting but quickly spiraled into a full feature marathon. Added a stripCountryCode() helper that handles those annoying 11-digit numbers people enter with the leading "1". Nothing fancy, but those little UX touches matter.
The mobile layout for route headers was driving me crazy, so I finally restructured it properly. Split everything into logical sections with proper flex-wrap so buttons don't get cramped on smaller screens. Tested at 375px and 430px breakpoints - should feel much better on phones now.
Email Notifications That Actually Work
Implemented intake form email notifications using SendGrid. The tricky part was detecting whether to use SnowTrack or LawnTrack branding - ended up using lawn_custom_slug matching which feels more reliable than client-side params. Wrapped the whole thing in try/catch because email failures should never block customer submissions.
That "New - From Form" badge was bugging me too. Now it shows the actual signup date and automatically hides after the customer's first completed service. Much cleaner.
Billing Gets Smarter
Added selective billing with checkboxes - sometimes you don't want to bill everything at once. The "Bill Selected (N)" button sits right next to "Bill All (N)" with a proper Select All toggle.
Bigger change was adding processing fees. Created a whole new table with migration 058, built out the API endpoints, and added a collapsible settings section. The print summary now shows gross revenue, processing fee breakdowns by payment method, and net totals. Real business metrics.
Found and fixed a nasty billing bug where extra charges weren't being included in Square billing. The endpoint was reading base prices instead of locked prices plus extra charges. Classic case of working in dev but failing with real data.
Accessibility Marathon
Went on a bit of an accessibility spree. Enlarged hamburger touch targets to proper 44x44px, added 80+ aria-labels across both apps, and built a reusable ConfirmModal component with focus management and escape key support.
Replaced every single alert() and confirm() call - we're talking 26 alerts and 5 confirms in StormMode alone. The new modals feel so much more professional.
Also enhanced all the empty states with proper icons, headings, and call-to-action buttons. Added keyboard navigation to settings sections and completed service cards. The apps just feel more polished now.
The Technical Bits
Moved the expenses form from a modal to an inline collapsible at the top of the page. The toggle switches between "+ Add Expense" and "- Close Form" which feels more intuitive. Edit still uses a modal since that workflow is different.
Used a global CSS approach for the touch target fixes rather than editing 10+ individual files. Sometimes the simple solution is the right solution.
Both repos are clean and pushed. SnowTrack hit commit f6acc50 and LawnTrack is at cdc9d02.
What's Next
Need to run migration 058 on production to create that payment_method_fees table. Also want to test the phone formatting edge cases and verify the SendGrid emails are actually delivering.
Days like this remind me why I love building in public. When you're in the flow, amazing things happen. On to the next sprint!