Eduin Garcia
Freelance project · Altafit Gym Club, Spain · 2018 – 2019

A member portal fora Spanish gym chain

Member-facing single-page application for Altafit Gym Club — login and account management, subscription and billing status, gym access history, class booking with a live schedule, activity timetable, member perks, training programmes (GBody / GBox), the “Club Corredor” content feed, news and club contact with maps.

The production member portal for Altafit Gym Club, built solo as a freelance project alongside full-time work at Melkart. The backend was a third-party gym-management API — I built the entire client and the integration layer over it.

Member dashboard — screenshot unavailable
My Altafit — application scaleReact 16 SPASheet 01
27
Pages
37
Routes
19
REST endpoints consumed
11
Domain models

~7.2k lines of JavaScript across 104 files. Fully responsive, mobile-first, four breakpoints. Spanish UI throughout.

01 · Architecture

Redux conventions over boilerplate

02 · Frontend

React 16.4 · Redux 4
Core
React 16.4, JavaScript (ES6+), Create React App 1.1 (react-scripts, Webpack/Babel)
Routing
React Router 4 + react-router-dom — nested Switch/Route trees, guarded areas, redirect fallbacks, 404 handling
State
Redux 4, React-Redux 5, redux-thunk, redux-promise-middleware, redux-logger, custom middleware
Styling
styled-components 3 (used in 43 files) + a central theme.js design-token class — brand palette, 4 media-query breakpoints, reusable CSS helpers
UI kit
Bootstrap 4 grid/utilities, Font Awesome 4 icons
Responsive
Mobile-first layout with react-responsive for component-level breakpoint logic, plus a dedicated mobile menu and slide-out left bar
Animation
react-motion spring animations, custom hover-animation and scroll-to-top components
Calendar
fullcalendar-reactwrapper — class timetable and bookable-session agenda
Maps
google-map-react — club locator on the contact page
HTTP
Axios with global default headers (platform key, API key, content type) behind a single utils/http module
Dates
Moment.js — schedule ranges, booking windows, access-history formatting
Notifications
AlertifyJS + an in-house Redux-driven notification component
Validation
string-validator for form and field checks (login, contact, password recovery)
Analytics
React GA — Google Analytics page-view tracking wired into the router
PWA
CRA service-worker registration + web app manifest (installable, standalone display)
Language
Spanish UI throughout — routes, copy and domain vocabulary

03 · Feature areas

27 pages · 37 routes
authLogin, password recovery (olvido-password), first-time password creation, temporary-access flow.
profileMember profile and personal data.
suscripcionSubscription plan, status and billing detail.
accesosGym entry/exit history.
reservasBooking and cancelling classes across clubs, rooms and agendas; class detail pages.
cuadrante-actividadesActivity timetable and class descriptions with intensity indicators.
ventajasMember perks and partner benefits.
entrenamientosTraining programme sections, including GBody and GBox.
club-corredorRunners-club content feed with category filtering, infinite scroll and detail views, gated by an entitlement check.
noticias / contactoNews feed and club contact form with map.

04 · Supporting services & delivery

Mock API · CRA build
Mock / proxy API

Express 4 on Node, used to develop against a stable local surface while the third-party gym API was in flux. Hardened with Helmet, CORS whitelisting for local dev origins, body-parser, Morgan request logging and request for upstream proxying, behind a Grunt + Nodemon watch pipeline with JSHint linting.

Tooling & integration

Yarn with a committed lockfile and the CRA build pipeline producing a hashed static bundle served behind a web server. Integrated against two third-party services: the userapi REST backend (/v2/…, token-in-path auth with platform and API-key headers) and a separate media/file server for images and documents.

05 · Engineering highlights

Six decisions
One generic reducer for every endpoint

The FETCHING/FETCHED/ERROR action-type convention plus a reducer factory removed ~19 near-identical reducers and made every screen's loading and error handling identical by construction.

Centralized session-expiry handling

Token invalidation is caught once in the Redux middleware pipeline and turned into a clean global logout, rather than re-implemented in every page's error branch.

Store-time session hydration

Reading localStorage before createStore means the app boots already authenticated, with no login flash or post-mount redirect.

Themed styled-components at scale

A static Styles class supplies colors, breakpoints and helpers (such as a truncate(width) mixin) to 43 styled-component files, keeping a single source of visual truth without a CSS framework rewrite.

Adapter layer over a third-party API

Model classes and a wrapped Axios instance isolate the app from an external, Spanish-named, token-in-URL API whose shape the project did not control.

Infinite-scroll content feed

Category filtering and paginated fetches, backed by the same generic API-state machinery as every other screen.

06 · Retrospective

Built 2018 – 2019

The portal ran in production for Altafit's members; the domain now hosts a later, non-React implementation by another vendor, which is why this page carries no screenshots.

It was built on the stack that was current then: React 16 class components, Redux with thunks and promise middleware, CRA 1.x, Bootstrap 4. Today's equivalents would be function components with hooks, TanStack Query or RTK Query in place of the custom request-state reducers, TypeScript for the API models and Vite instead of react-scripts — the architectural separations (adapter layer, generic request state, middleware-level session handling) map cleanly onto those modern tools.

Class booking — screenshot unavailable
Mobile view — screenshot unavailable
Previous: Caxper← All work