A sneaker store with no passwords

Front-end work on an online store for a premium footwear retailer — passwordless sign-in over two delivery channels, multi-facet catalogue filtering, and a request queue for stock that didn't exist yet.

Built with
React · Redux · Tailwind CSS · Razorpay · Fast2SMS
Role
Frontend UI Developer, team of five

The problem

An online store for one of India’s leading premium sportswear and footwear retailers, built for sneaker enthusiasts. I worked on the front end, in a team of five.

Two things about that shaped most of the interface, and neither is obvious to a reader outside India.

Nobody signs in with a password

The client specified one-time codes, and no password anywhere. There is no password field, no password strength meter, and no forgotten-password flow — because there is nothing to forget.

For an Indian consumer product this is the default rather than a novelty. Phone numbers are a primary identity and OTP is what users already expect. But the store ran two delivery channels: a code by SMS through Fast2SMS, and a code by email.

Two channels sounds like a small detail and is not. It doubles the delivery paths, doubles the failure modes, and creates a problem single-channel sign-in never has: the interface must tell the user which inbox to go and look in. Get that wrong and the user waits patiently on the wrong screen for a message that already arrived somewhere else.

The verification screen, showing which channel the code went to. The Gmail mark and the masked address are load-bearing, not decoration. They answer “where do I go and look?” before the user has to ask it.

The rest of the screen is the unglamorous part: four code inputs, a resend timer counting down so people do not hammer the button, expiry, and the fact that the message often arrives while the user is looking at a completely different app.

It also deletes a whole category of abandonment: nobody gives up at checkout because they cannot remember a password set eight months ago.

Filtering was the hard part

Not the cart, and not checkout. The catalogue filters.

Sneakers are filtered on size, brand, category, gender and colour simultaneously, and every one of those interacts with the others. Filter to a brand and the available sizes change. Filter to a size and most colours vanish. Each combination needs a result count, an empty state that explains which constraint emptied it, and a way back out that doesn’t reset everything the user has already chosen.

That is a state-management problem more than a visual one, and it is why this project used Redux rather than component state — filter selections, the derived result set, and the pagination on top of it all have to stay consistent while five independent controls change underneath them.

The catalogue: seven facet groups down the left, results to the right. Categories, brand, gender, a thirty-cell size grid, colour swatches, release year and price — all live at once, all affecting each other.

Two decisions made it work. Filter state lived in the URL, so a filtered view could be shared, bookmarked, and survived a reload — a filtered catalogue that forgets itself on refresh is a filtered catalogue nobody links to.

And the facets came from the server, not the browser. That is visible in the price filter, which shows a count beside every band. Those counts have to reflect the other filters currently applied, which means they cannot be precomputed on the client from a page of results — the server has to count across the whole matching set each time. It costs a round trip per change and buys the thing that makes faceted search usable: you can see which choice is a dead end before you make it.

Price bands, each showing how many products match. The counts are the tell. A number beside each band means the server counted the matching set — the browser could not know this from one page of results.

Payments

Checkout ran on Razorpay, an Indian gateway. Worth spelling out for a reader elsewhere: it fronts cards, netbanking, wallets and UPI, India’s real-time bank-to-bank rail, which is how a very large share of Indian e-commerce is actually paid.

The system confirmed payments by webhook rather than trusting the browser’s report of success — the server learned that a payment had settled from the gateway directly, which is the difference between an integration that survives a closed tab and one that does not. That part was built by teammates; I worked on the front end of the checkout flow.

The checkout screen. Multi-step checkout, with the payment step handing off to the gateway.

Asking for stock that doesn’t exist

The store carried a product request feature: users could ask for items the shop didn’t list. A request emailed the team.

For a general retailer that would be strange. For a sneaker store it is the whole culture — buyers hunt specific colourways and sizes that sell out in minutes, and a request queue turns “we don’t have it” into demand data somebody can act on. The interface is plain. The product decision is not.

Afterwards

The storefront is offline. www.collectxn.com now returns an expired-site placeholder, and I don’t know what happened to the business.

← All work