Building the User Interface for a Complex Platform
A platform with 86 domain entities, 100+ API endpoints, and features spanning event management, expense splitting, trip planning, and analytics needs a frontend that is both powerful and approachable. For Play The Event, the frontend is built with Angular 19, leveraging the latest features of the framework to deliver a fast, accessible, and maintainable user experience.
What You Will Learn in This Article
- Why Angular 19 with standalone components was chosen
- Signal-based reactive state management
- Server-Side Rendering (SSR) for performance and SEO
- 27 lazy-loaded modules and the routing architecture
- Responsive design strategy across devices
- Internationalization with 21 languages
- Rich UI components and accessibility considerations
Why Angular 19
The choice of Angular was driven by several factors. The platform is a large-scale application with complex forms, multiple interconnected views, and strict typing requirements. Angular's opinionated structure, built-in dependency injection, and first-class TypeScript support make it well-suited for this kind of project.
Angular 19 specifically brought stable Signals, improved SSR with hydration, and enhanced standalone component APIs that significantly reduced boilerplate compared to earlier versions.
Standalone Components: No NgModules
The entire frontend uses standalone components exclusively. There are no NgModules in the project. Every component declares its own imports, making dependencies explicit and enabling better tree-shaking. This approach also simplifies lazy loading, since each route can directly reference a standalone component without needing a wrapper module.
Signal-Based State Management
Angular Signals represent a paradigm shift in how reactive state is managed. Instead of relying on RxJS Observables for every piece of UI state, Signals provide a synchronous, fine-grained reactivity model that is easier to reason about and more performant for template rendering.
In Play The Event, Signals are used for:
- Component-local state: Form values, UI toggles, loading indicators
- Computed values: Derived data that updates automatically when dependencies change
- Service-level state: Shared state across components within a feature area
// Event detail component using Signals
export class EventDetailComponent {
private eventService = inject(EventService);
// Core signals
event = signal<Event | null>(null);
participants = signal<Participant[]>([]);
loading = signal(true);
// Computed signals (derived state)
confirmedCount = computed(() =>
this.participants().filter(p => p.status === 'CONFIRMED').length
);
pendingCount = computed(() =>
this.participants().filter(p => p.status === 'PENDING').length
);
attendanceRate = computed(() => {
const total = this.participants().length;
return total > 0
? Math.round((this.confirmedCount() / total) * 100)
: 0;
});
// Effect for side effects
constructor() {
effect(() => {
const evt = this.event();
if (evt) {
document.title = `${evt.name} - Play The Event`;
}
});
}
}
RxJS is still used for HTTP calls and WebSocket streams, but the results are typically fed into Signals at the boundary, keeping template code clean and synchronous.
Server-Side Rendering and Hydration
Performance is critical for a platform that users access on mobile devices at events. Play The Event uses Angular SSR to deliver pre-rendered HTML from the server, which is then hydrated on the client. This provides several benefits:
- Faster First Contentful Paint: Users see meaningful content before JavaScript loads
- SEO optimization: Search engine crawlers receive fully rendered HTML
- Improved Core Web Vitals: LCP and CLS scores benefit from pre-rendered content
- Social media previews: Open Graph tags are present in the initial HTML response
SSR Considerations
- Browser-only APIs (localStorage, window) are guarded with
isPlatformBrowserchecks - Map components (MapLibre) are loaded lazily only on the client side
- Authentication state is transferred from server to client via transfer state
- API calls made during SSR are cached and reused during hydration to avoid duplicate requests
27 Lazy-Loaded Modules
The application is organized into 27 lazy-loaded feature areas, each loaded on demand when the user navigates to the corresponding route. This keeps the initial bundle small and ensures that users only download the code they actually need.
LAZY-LOADED ROUTES (27 modules)
CORE
├── /auth → Login, Register, Password Reset
├── /dashboard → User dashboard, event overview
├── /profile → User profile, preferences, settings
└── /notifications → Notification center
EVENTS
├── /events/create → Event creation wizard
├── /events/:id → Event detail and management
├── /events/:id/guests → Participant management
├── /events/:id/rsvp → Public RSVP page
└── /events/:id/settings → Event settings and permissions
EXPENSES
├── /events/:id/expenses → Expense list and dashboard
├── /events/:id/expenses/new → Add new expense
├── /events/:id/settlements → Settlement tracking
└── /events/:id/budget → Budget overview
TRIPS
├── /events/:id/trips → Trip planner
├── /events/:id/trips/:tid → Trip detail with map
└── /events/:id/trips/stops → Stop management
AGILE
├── /events/:id/board → Task board (Kanban)
├── /events/:id/sprints → Sprint management
└── /events/:id/backlog → Product backlog
ANALYTICS
├── /events/:id/analytics → Event analytics dashboard
└── /analytics/global → Cross-event analytics
OTHER
├── /subscription → Stripe subscription management
├── /help → Help center and documentation
├── /legal → Terms, privacy, cookies
├── /landing → Public landing pages
└── /admin → Admin panel (role-gated)
Responsive Design Strategy
The platform supports three primary breakpoints with a mobile-first approach. Every component is designed to work on phone screens first, then progressively enhanced for tablet and desktop layouts.
Mobile (320px - 767px)
On mobile, the interface uses a single-column layout with a bottom navigation bar. Cards stack vertically, tables transform into card-based lists, and the map view takes the full screen. Touch targets are a minimum of 44px, and swipe gestures are supported for common actions like dismissing notifications or navigating between tabs.
Tablet (768px - 1023px)
The tablet layout introduces two-column grids for event cards, a collapsible side navigation, and split-view panels where the list appears on the left and details on the right. The map and itinerary views sit side by side.
Desktop (1024px+)
Desktop users get the full experience with a persistent sidebar, three-column grids, hover effects, keyboard shortcuts, and the embedded Univerjs spreadsheet at full width. The Kanban board for agile tasks displays all columns simultaneously.
Internationalization: 21 Languages
Play The Event supports 21 languages, covering the major European, Asian, and Middle Eastern markets. The internationalization system uses Angular's built-in i18n support combined with a custom translation service that loads language files on demand.
SUPPORTED LANGUAGES (21)
EUROPEAN
├── English (en) ├── French (fr)
├── Italian (it) ├── German (de)
├── Spanish (es) ├── Portuguese (pt)
├── Dutch (nl) ├── Polish (pl)
├── Romanian (ro) ├── Greek (el)
├── Czech (cs) ├── Hungarian (hu)
└── Swedish (sv)
ASIAN
├── Chinese Simplified (zh)
├── Japanese (ja)
├── Korean (ko)
└── Hindi (hi)
OTHER
├── Arabic (ar) ← RTL support
├── Turkish (tr)
├── Russian (ru)
└── Ukrainian (uk)
Arabic support required implementing full RTL (Right-to-Left) layout mirroring, including flipping navigation, adjusting padding and margins, and ensuring that icons and directional elements are properly reversed.
Rich UI Components
The frontend includes a comprehensive set of custom UI components built specifically for event management scenarios. These include:
- Seating chart editor: Drag-and-drop table and seat assignment with real-time collaboration
- Timeline view: Visual timeline for trip itineraries with zoom and pan
- Budget charts: Chart.js-powered visualizations for expense breakdowns
- Kanban board: Drag-and-drop task board with swimlanes for sprint planning
- Guest list: Searchable, filterable, sortable table with inline editing
- RSVP form: Public-facing form with custom fields and validation
- Notification center: Real-time notification panel with categories and read state
Accessibility
Accessibility is not an afterthought. The platform targets WCAG 2.1 AA compliance with the following measures:
Accessibility Features
- Semantic HTML5 elements throughout (nav, main, article, section)
- ARIA labels on all interactive elements without visible text
- Full keyboard navigation with visible focus indicators
- Color contrast ratios of 4.5:1 or higher for all text
- Screen reader announcements for dynamic content changes
- Reduced motion support via
prefers-reduced-motionmedia query - Skip-to-content links on every page
Key Takeaways
Lessons from Building the Frontend
- Signals simplify state: Moving from RxJS-heavy templates to Signals reduced complexity and improved readability
- Lazy loading is essential at scale: 27 modules keep the initial bundle under 200KB gzipped
- SSR pays dividends: Pre-rendered pages improve both SEO and perceived performance, especially on mobile
- Internationalization must be planned early: Adding 21 languages retroactively would have been far more expensive
- Mobile-first is not optional: Most event participants access the platform from their phones during the event itself
In the next article, we dive into the analytics and machine learning capabilities of Play The Event, exploring how a Python FastAPI microservice provides intelligent insights to organizers.
Related deep dive: 17 - AI, Analytics e Machine Learning: Decisioni Guidate dai Dati.
Related deep dive: 18 - Agile, Real-Time e Collaborazione in Tempo Reale.
Frequently asked questions
What is the framework used for building the frontend of Play The Event?
Angular 19.
Why was Angular chosen for this project?
The platform's complex forms, multiple interconnected views, and strict typing requirements made Angular a suitable choice due to its opinionated structure, built-in dependency injection, and first-class TypeScript support.
What is the purpose of using Signals in Play The Event?
Signals provide a synchronous, fine-grained reactivity model that is easier to reason about and more performant for template rendering, replacing the need for RxJS Observables for every piece of UI state.
How does Play The Event handle internationalization?
It uses Angular's built-in i18n support combined with a custom translation service that loads language files on demand, supporting 21 languages.
Commenti
Caricamento commenti...
Sign in to comment