Context
I was a senior software engineer and tech lead on Bizee’s platform team. Customers paid in two places: the order funnel and the customer dashboard. Each ran on its own legacy jQuery codebase. Every place that took a payment had its own form.
Payments were moving to Adyen, which encrypts card data in the browser. The backend engineers built the Adyen gateway on the server. Every card form in the browser had to change.
Problem
Four places took payments, spread across two jQuery codebases that shared no code. Besides taking the card, those pages carried their own logic for submitting the order, validating it and accepting the terms. Rewriting that logic was off the table.
I needed one payment UI that all four places could use without rewriting any of them.
What I did
I built one Vue payments component for all four places. It lists saved cards. New cards go through Adyen’s hosted card fields. I swapped the old forms out one page at a time, so each step could be reverted on its own. Cypress end-to-end tests covered card and PayPal payments.
The component knows nothing about the page that hosts it. It talks to the page through browser events. Each page got a small adapter that submits the order as before.
PayPal and Apple Pay came later, through Adyen, on the same contract. They appear next to the saved cards. When a customer picks one, its button takes the place of the page’s pay button. The page then submits the order. PayPal and Apple Pay each rolled out behind per-section feature flags.
Outcome
One component replaced two legacy jQuery payment stacks across four call sites. Customers could pay with a saved card, a new card, Apple Pay or PayPal, all through Adyen.
I retired 2,300 lines of legacy payment code. PayPal and Apple Pay shipped without changing how any page submitted its orders. Card numbers were typed into Adyen’s hosted fields, so our pages only handled encrypted values.
Stack
Vue, JavaScript, Adyen, PHP