Megaworld Hotels & Resorts — Corporate Website & Multi-Brand Platform

A multi-brand hotel corporate website for Megaworld Hotels & Resorts — built with Vue.js and TypeScript, featuring brand-specific theming, CMS-driven content, a live booking form, and deployed on AWS CloudFront.
Megaworld Hotels & Resorts — Corporate Website & Multi-Brand Platform

Project Overview

Megaworld Hotels & Resorts (MHR) is a Philippine-based hotel management company operating a portfolio of upscale hotel brands across key lifestyle and business districts. This project is their primary digital presence — a corporate website and marketing platform serving both leisure travellers and corporate clients across three distinct brands: Savoy Hotels, Belmont Hotels, and Richmonde Hotels.

Beyond brand storytelling, the platform handles promotions, dining discovery, event and venue listings, press and editorial content, a loyalty membership program (Club Access), a careers portal, and a sustainability section — all powered by a live CMS backend (api.pbahotels.com/megaworld) and deployed globally via AWS CloudFront.

Business Outcomes

  • Consolidated three hotel brands and a dedicated campaign site (Boracay Newcoast) into a single codebase, reducing duplication and long-term maintenance cost
  • Enabled the marketing team to independently publish and update promotions, press releases, blog posts, dining content, and event listings without engineering involvement
  • Surfaced a hotel booking entry point directly on the homepage, reducing friction for travellers discovering the brand organically
  • Improved social discoverability through per-page Open Graph meta tag management, contributing to higher click-through rates from social sharing
  • Provided real-time user behaviour visibility via Google Tag Manager, with structured event tracking on booking interactions and page navigation
  • Created a dedicated MICE campaign (Boracay Newcoast) with its own isolated route and visual identity, supporting B2B event sales

What I Built

  • Multi-brand SPA — a single Vue.js application housing four distinct experiences (MHR, Savoy, Belmont, Richmonde) plus a Boracay Newcoast MICE campaign, each with its own layout, route tree, SCSS theme, and content pipeline
  • Homepage booking form — interactive hotel search with destination autocomplete, check-in/check-out date range picker, and room/guest selectors, wired to GTM event tracking (gtagBookEvent)
  • Promotions system — filterable Room and F&B promotions with hotel-level filtering, load-more pagination, and detail pages for individual offers, venues, and events
  • Dining section — Swiper-driven gallery with categorised F&B listings, load-more support, and CMS-managed content
  • Events & venues — venue showcase with event listings and dedicated detail pages, targeted at corporate/MICE buyers
  • Features hub (Press & Blog) — sortable and paginated press release and blog article listings with individual content detail pages
  • Club Access loyalty section — membership programme overview with tiered benefits display
  • Careers portal — hotel-grouped job listings with expandable position descriptions and direct contact details (phone/email)
  • Sustainability page — video-background section covering MHR's mindful stay programme and environmental commitments
  • Newsletter subscription — API-backed subscriber capture form
  • Brand landing pages — Savoy, Belmont, and Richmonde each with dedicated sub-routes and brand-specific visual identity

Stack

Layer

Technology

Framework

Vue.js 2.6, TypeScript 4.9

State Management

Vuex 3

UI Library

Vuetify 2.5 (Material Design)

Routing

Vue Router 3

Carousel / Sliders

Swiper 6

HTML Sanitization

DOMPurify 3

SEO / Meta

vue-meta 2

Analytics

Google Tag Manager (GTM-553LD59C)

Icons

Font Awesome 6

Build Tooling

Vue CLI 5, Webpack 5, Babel 7

Package Manager

pnpm

Infrastructure

AWS S3 + CloudFront, AWS CodeBuild CI/CD

Rendering Strategy

Client-Side Rendering (CSR) SPA deployed as a static asset bundle on AWS S3, served globally through CloudFront.

  • Routes are lazy-loaded via dynamic import() to keep initial bundle lean; each brand and campaign is a separate async chunk
  • Page-level metadata (title, description, Open Graph) is managed through Vuex and applied at runtime via vue-meta, enabling per-route social sharing previews
  • Hero video uses AV1 with H.264 fallback and a poster image to prevent layout shift on load
  • Vuetify is tree-shaken at build time; prefetch hints are disabled to avoid unnecessary preloads
  • File hashing is disabled to support controlled CloudFront cache invalidation on each deploy

Key Engineering Challenges Solved

1. Multi-brand isolation within a single SPA Four hotel brands and a campaign site share one codebase but require completely independent visual identities, layouts, and content. Each brand is structured as its own route namespace with a dedicated layout component and scoped SCSS entry — co-located but never bleeding into each other.

2. Safe rendering of CMS-sourced rich text The CMS returns arbitrary HTML for body copy and descriptions. Rendering this naively opens XSS vectors. Built a useSanitize composable wrapping DOMPurify that strips unsafe tags and attributes before any CMS content touches the DOM, while preserving intentional rich text formatting.

3. Dynamic media URL handling Content editors reference images, videos, and YouTube embeds inconsistently across CMS fields. Built a mediaUrl utility that detects URL type, validates format, and transforms raw strings into the correct embed or asset URL — preventing broken media without requiring editorial discipline.

4. JWT authentication across all API calls All backend endpoints require Bearer token authentication. Centralised this in a shared Axios instance with the token injected from environment variables, so no individual service file handles auth logic — and rotating the token is a one-line config change.

5. GTM event tracking on booking interactions The booking form needed to fire structured GTM events on destination select, date pick, and form submission without coupling analytics logic to UI components. Solved by abstracting GTM pushes (gtagBookEvent) into discrete tracking calls triggered from Vuex actions, keeping components clean and testable.

6. CloudFront cache invalidation on deploy Static SPA deployments on CloudFront can serve stale files if the cache isn't cleared post-deploy. The AWS CodeBuild pipeline runs an automatic CloudFront invalidation after every successful build, with Google Chat notifications on success or failure — giving the team confidence that deployments are live without manual intervention.

2025
Vue.jsTypeScriptVuexVuetifyMulti-BrandCMS IntegrationHotel & HospitalityBooking SystemAWS CloudFrontAWS S3CI/CDREST APIGoogle Tag ManagerSEOResponsive DesignSPAMICE
Mohammad Sulthan • Built with Nuxt + Sanity • © 2026