Loading…
Loading…
Chalet Retreat is a production-focused software project built by Sadam Hussain using Next.js, TypeScript, Material UI, and related technologies.
Luxury rental platform on Next.js and TypeScript: map-based discovery with clustering, layered image optimization, multi-step Stripe booking. Outcome: craft under constraints, rich media with fast pages.
Tech Stack




Status
Production Ready
Type
Enterprise platform
Architected and led the development of a premium luxury rental platform using Next.js and TypeScript, delivering a high-performance frontend that balances visual richness with fast page loads across image-heavy property listings.
Engineered an interactive property discovery experience with Google Maps API, implementing custom marker rendering, client-side marker clustering for dense geographic regions, and synchronized map-list state so that map interactions update listing views and vice versa.
Implemented a multi-step Stripe booking flow with progressive disclosure (property selection → date/guest configuration → payment → confirmation), React Hook Form validation at each step, and secure tokenized payment handling for high-value vacation transactions.
Built a comprehensive image optimization pipeline using Next.js Image component with responsive srcsets, blur placeholder generation, intersection-observer-based lazy loading, and CDN-backed caching to handle pages displaying dozens of high-resolution property photos.
Developed a premium design system using Material UI as the component foundation with SASS modules for custom theming, ensuring visual consistency across property cards, galleries, booking modals, and marketing surfaces.
Implemented client-side state management with Redux Toolkit for global application state (search filters, map viewport, user session) and React Query for server state (property listings, availability, pricing) with cache invalidation on search parameter changes.
Established unit and integration testing workflows with Jest and React Testing Library for component behavior, alongside Cypress for end-to-end verification of the complete booking journey from property discovery through payment confirmation.
Optimized rendering performance through route-based code splitting, dynamic imports for heavy components (map, image galleries), and strategic SSR/CSR decisions per page type - SSR for property detail pages (SEO), CSR for interactive map views (interactivity).
Delivered a mobile-optimized discovery experience with touch-friendly map interactions, swipeable property galleries, and a responsive layout that adapts the map-list split view for smaller screens.
Implemented geographic search with bounding-box queries that re-fetch listings as the user pans and zooms the map, with debounced API calls and optimistic UI updates to prevent jarring content reloads during exploration.
Chalet Retreat is a luxury vacation rental platform where media performance was designed in, not patched on. Dozens of high-resolution photos per listing load through a layered pipeline: responsive sizing, blur placeholders, lazy loading, CDN caching. Map-based discovery with client-side clustering stays smooth at any zoom, and a multi-step Stripe flow closes high-value bookings.
The product combines sophisticated visual storytelling, interactive map-based discovery with real-time geographic filtering, and a polished multi-step booking experience to help travelers discover and reserve upscale chalet properties. The frontend manages complex state synchronization between the map view and listing views, ensuring that geographic exploration and traditional list browsing remain perfectly in sync.
Luxury rental platforms face a unique challenge: the digital experience must mirror the premium nature of the physical properties. A slow-loading page or a janky map interaction immediately undermines the brand promise. Discovery needs to be visual and intuitive, while the technical foundation must remain fast despite being extremely image-heavy.
The core problem: High-end property listings are inherently media-intensive - each listing features dozens of professional photographs, virtual tours, and detailed amenity descriptions. Traditional approaches to rendering these pages either sacrifice visual quality (low-res thumbnails, limited galleries) for speed, or sacrifice speed (full-resolution images, no lazy loading) for quality. The platform needed both.
Stakeholder perspective:
Constraints that shaped the architecture:
Image performance in Chalet Retreat isn't a set of optimization tricks applied after the fact - it's built into the component architecture. Every component that renders an image uses a shared OptimizedImage wrapper that handles responsive sizing, lazy loading, blur placeholders, and error fallbacks. This wrapper abstracts the complexity of Next.js Image configuration so that developers adding new image-heavy features automatically get optimized rendering without thinking about it.
The key insight is that in an image-heavy application, media optimization must be the default, not an opt-in. If developers have to remember to add lazy loading and responsive sizing, some will forget, and performance degrades gradually.
The map and listing views share a single source of truth for the current search context (geographic bounds, filters, sort order). This state lives in Redux Toolkit, and both views subscribe to it reactively. When the map viewport changes, the geographic bounds update in the store, which triggers a React Query refetch with the new bounding box, which updates the listing view. Conversely, selecting a listing updates the map's center coordinates.
This bidirectional synchronization required careful debouncing - map panning fires rapid viewport change events, and refetching listings on every frame would overwhelm the API. A 300ms debounce on viewport changes provides a responsive feel without excessive network calls.
Payment security follows Stripe's recommended architecture:
The most architecturally interesting challenge was building a responsive, performant map discovery experience that handles thousands of property markers while synchronizing with a filterable listing panel.
The Problem: Rendering thousands of markers on a Google Map causes severe performance degradation - each marker is a DOM element, and the map becomes unresponsive with more than a few hundred visible markers. Simultaneously, the listing panel needs to show results corresponding to the visible map area, and interactions in either view must update the other in real-time.
The Architecture:
Client-Side Marker Clustering: Instead of rendering individual markers for every property, the system uses a client-side clustering algorithm that groups nearby markers based on the current zoom level. At city-level zoom, users see cluster badges ("47 properties") that expand into individual markers as they zoom in. The clustering recalculates on every zoom/pan event, using a spatial index (grid-based) for efficient nearest-neighbor grouping.
Bounding-Box Queries: Rather than loading all properties globally, the system queries for properties within the map's current viewport bounds. As the user pans, the visible bounding box changes, and a debounced query fetches the new set of properties. React Query caches previous bounding-box results, so revisiting a previously viewed area renders instantly from cache while revalidating in the background.
Virtualized Listing Panel: The listing panel uses virtualization (rendering only the DOM elements visible in the scroll viewport) so that a search returning hundreds of results doesn't create hundreds of DOM nodes simultaneously. Combined with property card image lazy loading, the listing panel remains smooth regardless of result count.
Interaction Synchronization: Map clicks, marker hovers, and listing panel interactions all dispatch to the same Redux store slice. Hovering over a listing highlights its marker on the map. Clicking a marker scrolls the listing panel to the corresponding card. This shared state model ensures both views always reflect the same selection and filter context.
Performance Budget: The entire map interaction loop (pan → debounce → API call → cluster → render markers → update listings) targets a 500ms end-to-end latency budget. API response time is the bottleneck, so the bounding-box query is optimized server-side with spatial indexes, and the client pre-renders cached results while the fresh query resolves.
Why this approach: The simpler alternatives (loading all markers at once, or using server-side marker tiling) either break on large datasets or require infrastructure complexity that wasn't justified. Client-side clustering with bounding-box queries provides the right balance - the map feels responsive at any zoom level, the API serves manageable result sets, and the UX is seamless.
Challenge: Property pages with 20-30 high-resolution images took several seconds to load, degrading the premium browsing experience. Approach: Built a multi-layer image optimization pipeline - responsive srcsets serve appropriately sized images per device, blur placeholders provide instant visual feedback, intersection-observer lazy loading prevents off-screen images from loading, and a CDN caches optimized variants. Why: No single optimization technique is sufficient for heavily image-laden pages. The layered approach ensures that each optimization handles a different aspect of the problem (bandwidth, perceived load time, browser resource usage, cache efficiency).
Challenge: Thousands of map markers caused the Google Maps rendering to become sluggish, with frame drops during pan and zoom interactions. Approach: Implemented client-side marker clustering that groups nearby markers at higher zoom levels, reducing the visible DOM element count from thousands to dozens. The clustering algorithm recalculates efficiently on viewport changes using a grid-based spatial index. Why: The naive approach (render all markers) scales poorly because each marker is a separate DOM element with event listeners. Clustering reduces rendering cost while preserving the ability to discover individual properties by zooming in.
Challenge: The multi-step booking flow needed to maintain state across steps (dates, guests, payment) while allowing back-navigation without data loss. Approach: Used React Hook Form with a shared form context across all booking steps. Each step validates independently, but the form state persists across step transitions. Draft booking data is also saved to sessionStorage for recovery if the user accidentally navigates away. Why: Rebuilding form state on back-navigation is a common source of checkout frustration. Persistent form context eliminates this while sessionStorage provides a safety net for accidental page closures during high-value transactions.
Challenge: Map panning fires rapid viewport change events, and refetching property listings on every event would overwhelm the API and cause UI flickering. Approach: Debounced viewport change events by 300ms before triggering API refetches. During the debounce window, the previous listing results remain visible. React Query's stale-while-revalidate behavior shows cached results immediately when revisiting previously viewed areas. Why: The balance between responsiveness and efficiency requires debouncing - too short and the API is overwhelmed, too long and the UI feels laggy. 300ms provides responsive-feeling updates without excessive network calls.
Chalet Retreat reinforced that in premium markets, performance is a design requirement, not a technical metric. A luxury property loses its appeal if the page is slow to load or the map feels sluggish. This project proved that through careful rendering decisions and systematic media optimization, a visually immersive experience can coexist with top-tier technical performance.
Patterns I'd reuse:
OptimizedImage wrapper pattern that makes media optimization the default for every developer, not an opt-in. In any image-heavy application, this prevents gradual performance degradation as the team adds new features.What I'd reconsider:
Trade-offs acknowledged: