Files

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

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:

  1. Tries to fetch from API endpoint
  2. On error, falls back to local assets/data/profiles.json
  3. Caches data in memory
  4. 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:

  1. Verify image exists:

    ls -la src/assets/images/profile/
    
  2. 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
    }
    
  3. 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



Need Help? Check the root troubleshooting section or backend documentation for API-related issues.