Looking - Frontend Application
Ionic 3 / Angular 5 mobile application for browsing dating app profiles and stories
This is the frontend mobile application for the "Looking" art project. Built with Ionic 3 and Angular 5, it provides an interactive interface for exploring user profiles, stories, and messages about modern gay dating culture.
📋 Table of Contents
- Overview
- Tech Stack
- Project Structure
- Pages & Components
- Services
- Data Flow
- Development
- Building
- Troubleshooting
🎯 Overview
The frontend is a hybrid mobile application that can run as:
- Web application (development mode on port 8100)
- iOS native app (requires Xcode)
- Android native app (requires Android Studio)
Key Features:
- Grid-based profile browsing (Tinder-like swipe interface)
- Detailed profile views with images and user stories
- Message threads with conversation history
- Story submission form ("Tell Your Story")
- Tab-based navigation
- Offline support with local JSON fallback
🛠 Tech Stack
| Technology | Version | Purpose |
|---|---|---|
| Ionic Framework | 3.9.2 | Hybrid mobile framework |
| Angular | 5.0.3 | Component framework |
| TypeScript | 2.4.2 | Type-safe JavaScript |
| RxJS | 5.5.2 | Reactive programming |
| @angular/http | 5.0.3 | HTTP client (deprecated, pre-HttpClient) |
| ionic-swipe-all | 1.2.0 | Swipe gesture library |
| moment | 2.21.0 | Date/time formatting |
| @ionic/storage | 2.1.3 | Local storage abstraction |
| ionicons | 3.0.0 | Icon library |
Build Tool: @ionic/app-scripts 3.2.4 (Ionic's custom webpack wrapper)
📁 Project Structure
app/
├── src/
│ ├── app/ # Root application module
│ │ ├── app.component.ts # Root component (title: "Urnings")
│ │ ├── app.module.ts # Main NgModule with declarations
│ │ ├── app.html # Root template
│ │ ├── app.scss # Global styles
│ │ └── main.ts # Bootstrap entry point
│ │
│ ├── pages/ # Page components (routable views)
│ │ ├── tabs/ # Tab navigation container
│ │ │ ├── tabs.ts # TabsPage component
│ │ │ └── tabs.html # Tab layout (3 tabs)
│ │ │
│ │ ├── grid/ # Profile grid view (main browse page)
│ │ │ ├── grid.ts # Grid logic with swipe handling
│ │ │ ├── grid.html # Grid layout with profile cards
│ │ │ └── grid.scss # Grid styles
│ │ │
│ │ ├── profile/ # Detailed profile view
│ │ │ ├── profile.ts # Profile display logic
│ │ │ ├── profile.html # Profile template (name, age, about, pics)
│ │ │ └── profile.scss # Profile styles
│ │ │
│ │ ├── chat/ # Individual conversation view
│ │ │ ├── chat.ts # Chat message display
│ │ │ ├── chat.html # Message thread UI
│ │ │ └── chat.scss # Chat bubble styles
│ │ │
│ │ ├── messages/ # Message list/inbox view
│ │ │ ├── messages.ts # Message list logic
│ │ │ ├── messages.html # List of conversations
│ │ │ └── messages.scss # Message list styles
│ │ │
│ │ ├── users/ # User list view
│ │ │ ├── users.ts # User list logic
│ │ │ ├── users.html # User grid/list
│ │ │ └── users.scss # User list styles
│ │ │
│ │ ├── lightbox/ # Full-screen image viewer
│ │ │ ├── lightbox.ts # Image zoom/pan logic
│ │ │ ├── lightbox.html # Fullscreen image display
│ │ │ └── lightbox.scss # Lightbox styles
│ │ │
│ │ ├── information/ # Info/about page
│ │ │ ├── information.ts # Static info page
│ │ │ ├── information.html # Project information
│ │ │ └── information.scss # Info page styles
│ │ │
│ │ └── tell/ # Story submission form
│ │ ├── tell.ts # Form submission logic
│ │ ├── tell.html # Story submission form
│ │ └── tell.scss # Form styles
│ │
│ ├── services/ # Shared services
│ │ └── profiles.ts # ProfileService for data management
│ │
│ ├── theme/ # Global theme configuration
│ │ └── variables.scss # Ionic theme variables
│ │
│ ├── assets/ # Static assets
│ │ ├── data/ # Local JSON data files (fallback)
│ │ │ ├── profiles.json # All profiles
│ │ │ ├── profiles initial.json # Initial seed data
│ │ │ └── cruises.json # Additional data
│ │ ├── icon/ # App icons
│ │ ├── images/ # Profile, message images
│ │ │ ├── profile/ # Profile photos
│ │ │ ├── message/ # Message attachments
│ │ │ └── cruise/ # Cruise-related images
│ │ └── imgs/ # UI images and icons
│ │
│ ├── index.html # Main HTML entry
│ ├── manifest.json # PWA manifest
│ └── service-worker.js # Service worker for offline support
│
├── www/ # Build output directory
│ ├── build/ # Compiled JS/CSS bundles
│ │ ├── main.js # Application code
│ │ ├── vendor.js # Third-party libraries
│ │ ├── polyfills.js # Browser polyfills
│ │ └── main.css # Compiled styles
│ └── assets/ # Copied static assets
│
├── package.json # Dependencies and scripts
├── ionic.config.json # Ionic CLI configuration
├── tsconfig.json # TypeScript compiler config
├── tslint.json # TSLint rules (deprecated)
└── .editorconfig # Editor formatting rules
📄 Pages & Components
TabsPage (pages/tabs/)
Root navigation container with three tabs:
// tabs.ts - Tab configuration
tabs = [
{ root: GridPage, tabTitle: "Grid", tabIcon: "grid" },
{ root: UsersPage, tabTitle: "Users", tabIcon: "people" },
{ root: MessagesPage, tabTitle: "Messages", tabIcon: "chatboxes" },
];
GridPage (pages/grid/)
Main profile browsing interface - Tinder-like grid:
- Displays profile thumbnails in grid layout
- Supports swipe gestures (using
ionic-swipe-all) - Taps open detailed profile view
- Loads profiles from ProfileService
- Falls back to local JSON if API unavailable
Key Features:
- Swipe left/right for navigation
- Pull-to-refresh
- Infinite scroll
- Click thumbnail → ProfilePage
ProfilePage (pages/profile/)
Detailed profile view with:
- Profile photo (large detail image)
- Name, age, location
- "About" section with user story
- Multiple photos in gallery
- Message thread (if profile has messages)
- Navigation to previous/next profile
Navigation:
- Receives profile ID via NavParams
- "Next" and "Previous" buttons
- Photo gallery opens LightboxPage
ChatPage (pages/chat/)
Message thread view:
- Displays conversation history
- Question/answer format
- User responses vs. interviewer questions
- Image attachments supported
- Timestamps with moment.js
Message Types:
isUser: false→ Questions (left-aligned)isUser: true→ User responses (right-aligned)
MessagesPage (pages/messages/)
Inbox/conversation list:
- Shows all profiles with messages
- Displays message preview
- Unread indicators
- Tap to open ChatPage with full thread
UsersPage (pages/users/)
User list view:
- Alternative view to grid
- List format with thumbnails
- Quick access to profiles
- Filter/search options (if implemented)
LightboxPage (pages/lightbox/)
Full-screen image viewer:
- Zoom and pan gestures
- Swipe between photos
- Close button returns to profile
- Supports pinch-to-zoom
InformationPage (pages/information/)
Static information page:
- About the art project
- Artist statement
- Project goals
- Credits and acknowledgments
TellPage (pages/tell/)
Story submission form:
- Users can submit their own stories
- Form fields: name, age, location, story
- Photo upload
- Submission sends to API (if connected)
🔌 Services
ProfileService (services/profiles.ts)
Central data management service for profiles.
Endpoints:
endpoint: "http://localhost:27017/urnings/profiles"; // Primary API
fallback: "assets/data/profiles.json"; // Local fallback
epSubmitted: "/submitted"; // Submitted profiles
epVerified: "/verified"; // Verified profiles
Methods:
load(); // Load all profiles
loadSubmitted(); // Load submitted (pending) profiles
loadVerified(); // Load verified (approved) profiles
getProfiles(); // Get cached profiles
getProfileById(id); // Get specific profile
getNextProfile(id); // Navigate to next profile
getPreviousProfile(id); // Navigate to previous
Data Flow:
- Tries to fetch from API endpoint
- On error, falls back to local
assets/data/profiles.json - Caches data in memory
- Builds ID→index map for navigation
Fallback Behavior:
doGetRequest(endpoint, resolve, type) {
this.http.get(endpoint).subscribe(
(data) => { /* Use API data */ },
(error) => {
// API failed → use local JSON
this.doGetRequest(this.fallback, resolve, type);
}
);
}
🔄 Data Flow
Profile Loading Flow
graph TD
A[GridPage loads] --> B{ProfileService.load}
B --> C[Try API: http://localhost:27017/urnings/profiles]
C --> D{API Success?}
D -->|Yes| E[Store profiles in memory]
D -->|No| F[Fallback to assets/data/profiles.json]
F --> E
E --> G[Build ID-to-index map]
G --> H[Return profiles to GridPage]
H --> I[Display grid of thumbnails]
I --> J[User taps profile]
J --> K[Navigate to ProfilePage with ID]
K --> L[ProfilePage fetches profile from service]
L --> M[Display full profile details]
Message Loading Flow
graph TD
A[ProfilePage loads] --> B[Get profile by ID]
B --> C{Profile has messages?}
C -->|Yes| D[Extract messages array]
C -->|No| E[Show 'No messages']
D --> F[Display in ChatPage]
F --> G[Format with moment.js]
G --> H[Render question/answer pairs]
💻 Development
Start Dev Server
# From project root
npm run dev:app
# Or from app directory
cd app
ionic serve --host=0.0.0.0 --port=8100
Access: http://localhost:8100
Live Reload
Ionic's dev server watches for file changes and automatically:
- Recompiles TypeScript
- Rebuilds SCSS
- Reloads browser
- Preserves dev tools open
Chrome DevTools
Open Chrome DevTools to:
- Inspect components
- Debug TypeScript (source maps enabled)
- Test responsive layouts
- Simulate mobile devices
- Monitor network requests
API Configuration
To switch between local and remote API:
Edit services/profiles.ts:
// Local API (backend running on port 3069)
endpoint: "http://localhost:3069/profiles";
// Remote API (production)
endpoint: "https://api.pfosi.mifi.dev/profiles";
// Fallback (always local)
fallback: "assets/data/profiles.json";
🏗️ Building
Development Build
npm run build
# or
ionic build
Output: www/ directory
Production Build
ionic build --prod
Optimizations:
- Minification
- Tree shaking
- Ahead-of-time (AOT) compilation
- CSS purging
- Source map generation (optional)
Build for Mobile Platforms
iOS:
ionic cordova build ios --prod --release
# Requires Xcode and iOS development certificates
Android:
ionic cordova build android --prod --release
# Requires Android Studio and signing keys
Note: Mobile builds require additional Cordova setup not covered here.
🔧 Troubleshooting
node-sass Build Failed
Error:
Error: `gyp` failed with exit code: 1
Module 'node-sass' not found
Solution:
# node-sass requires Python 2.7 (included in DevContainer)
# If running locally:
npm rebuild node-sass --force
# Or use legacy peer deps
npm install --legacy-peer-deps
Why? node-sass is a native module that requires Python 2.7 and build tools. The DevContainer includes these dependencies via symlinks.
Peer Dependency Warnings
Error:
npm WARN ERESOLVE overriding peer dependency
Solution:
# Use legacy peer dependency resolution (npm 7+)
npm install --legacy-peer-deps
Why? Ionic 3 and Angular 5 were built before npm 7's strict peer dependency checking. The --legacy-peer-deps flag uses npm 6 behavior.
Module Not Found Errors
Error:
Error: Cannot find module '@angular/core'
Solution:
# Remove node_modules and reinstall
rm -rf node_modules package-lock.json
npm install --legacy-peer-deps
JavaScript Heap Out of Memory
Error:
FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed
Solution:
# Increase Node.js memory limit
export NODE_OPTIONS="--max-old-space-size=4096"
npm run ionic:serve
Ionic Serve Port Already in Use
Error:
Error: Port 8100 is already in use
Solution:
# Find process using port 8100
lsof -i :8100
# Kill the process
kill -9 <PID>
# Or use different port
ionic serve --port=8101
TypeScript Compilation Errors
Error:
Error: TS2304: Cannot find name 'Promise'
Solution:
# Verify TypeScript version matches project
npm install typescript@2.4.2 --save-dev --save-exact
Check tsconfig.json:
{
"compilerOptions": {
"lib": ["es2015", "dom"],
"target": "es5"
}
}
CORS Errors in Browser
Error:
Access to XMLHttpRequest at 'http://localhost:3069/profiles' blocked by CORS policy
Solution:
Option 1: Backend already allows all origins:
// backend/src/app.js
res.header("Access-Control-Allow-Origin", "*");
Option 2: Use Ionic's proxy (for dev server):
Edit ionic.config.json:
{
"proxies": [
{
"path": "/api",
"proxyUrl": "http://localhost:3069"
}
]
}
Update service:
endpoint: "/api/profiles"; // Proxied through dev server
Images Not Loading
Error:
404 Not Found: http://localhost:8100/assets/images/profile/john.png
Solutions:
-
Verify image exists:
ls -la src/assets/images/profile/ -
Check path in data:
// Should be relative to assets/images/ "pic": { "thumb": "profile/john_thumbnail.png", // ✅ Correct "detail": "/profile/john_detail.png" // ❌ Leading slash breaks it } -
Rebuild to copy assets:
ionic build
Service Worker Issues (Offline Mode)
Problem: Stale data cached, changes not appearing
Solution:
# Clear service worker cache in Chrome DevTools
Application → Storage → Clear site data
# Or disable service worker during development
# Comment out service worker registration in index.html
Ionic CLI Not Found
Error:
ionic: command not found
Solution:
# Install Ionic CLI globally (included in DevContainer)
npm install -g @ionic/cli
# Verify installation
ionic --version
📚 Additional Resources
- Ionic 3 Documentation: https://ionicframework.com/docs/v3/
- Angular 5 Documentation: https://v5.angular.io/docs
- TypeScript Documentation: https://www.typescriptlang.org/docs/handbook/basic-types.html
- RxJS 5 Documentation: https://rxjs-dev.firebaseapp.com/api
🔗 Related Documentation
- Root README - Project overview and quick start
- Backend README - API server documentation
- API Reference - REST API endpoints
- Database Schema - MongoDB collections
- DevContainer Guide - Development environment
- Deployment Guide - Production deployment
Need Help? Check the root troubleshooting section or backend documentation for API-related issues.