714 lines
18 KiB
Markdown
714 lines
18 KiB
Markdown
# 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](#overview)
|
|
- [Tech Stack](#tech-stack)
|
|
- [Project Structure](#project-structure)
|
|
- [Pages & Components](#pages--components)
|
|
- [Services](#services)
|
|
- [Data Flow](#data-flow)
|
|
- [Development](#development)
|
|
- [Building](#building)
|
|
- [Troubleshooting](#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:
|
|
|
|
```typescript
|
|
// 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:**
|
|
|
|
```typescript
|
|
endpoint: "http://localhost:27017/urnings/profiles"; // Primary API
|
|
fallback: "assets/data/profiles.json"; // Local fallback
|
|
epSubmitted: "/submitted"; // Submitted profiles
|
|
epVerified: "/verified"; // Verified profiles
|
|
```
|
|
|
|
**Methods:**
|
|
|
|
```typescript
|
|
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:**
|
|
|
|
```typescript
|
|
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
|
|
|
|
```mermaid
|
|
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
|
|
|
|
```mermaid
|
|
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
|
|
|
|
```bash
|
|
# 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`:**
|
|
|
|
```typescript
|
|
// 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
|
|
|
|
```bash
|
|
npm run build
|
|
# or
|
|
ionic build
|
|
```
|
|
|
|
Output: `www/` directory
|
|
|
|
### Production Build
|
|
|
|
```bash
|
|
ionic build --prod
|
|
```
|
|
|
|
**Optimizations:**
|
|
|
|
- Minification
|
|
- Tree shaking
|
|
- Ahead-of-time (AOT) compilation
|
|
- CSS purging
|
|
- Source map generation (optional)
|
|
|
|
### Build for Mobile Platforms
|
|
|
|
**iOS**:
|
|
|
|
```bash
|
|
ionic cordova build ios --prod --release
|
|
# Requires Xcode and iOS development certificates
|
|
```
|
|
|
|
**Android**:
|
|
|
|
```bash
|
|
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:**
|
|
|
|
```bash
|
|
# 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:**
|
|
|
|
```bash
|
|
# 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:**
|
|
|
|
```bash
|
|
# 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:**
|
|
|
|
```bash
|
|
# 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:**
|
|
|
|
```bash
|
|
# 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:**
|
|
|
|
```bash
|
|
# Verify TypeScript version matches project
|
|
npm install typescript@2.4.2 --save-dev --save-exact
|
|
```
|
|
|
|
**Check `tsconfig.json`:**
|
|
|
|
```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:
|
|
|
|
```javascript
|
|
// backend/src/app.js
|
|
res.header("Access-Control-Allow-Origin", "*");
|
|
```
|
|
|
|
**Option 2**: Use Ionic's proxy (for dev server):
|
|
|
|
**Edit `ionic.config.json`:**
|
|
|
|
```json
|
|
{
|
|
"proxies": [
|
|
{
|
|
"path": "/api",
|
|
"proxyUrl": "http://localhost:3069"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
**Update service:**
|
|
|
|
```typescript
|
|
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:**
|
|
|
|
```bash
|
|
ls -la src/assets/images/profile/
|
|
```
|
|
|
|
2. **Check path in data:**
|
|
|
|
```json
|
|
// 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:**
|
|
```bash
|
|
ionic build
|
|
```
|
|
|
|
---
|
|
|
|
### Service Worker Issues (Offline Mode)
|
|
|
|
**Problem**: Stale data cached, changes not appearing
|
|
|
|
**Solution:**
|
|
|
|
```bash
|
|
# 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:**
|
|
|
|
```bash
|
|
# 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](../README.md) - Project overview and quick start
|
|
- [Backend README](../backend/README.md) - API server documentation
|
|
- [API Reference](../backend/API.md) - REST API endpoints
|
|
- [Database Schema](../backend/SCHEMA.md) - MongoDB collections
|
|
- [DevContainer Guide](../.devcontainer/README.md) - Development environment
|
|
- [Deployment Guide](../DEPLOYMENT.md) - Production deployment
|
|
|
|
---
|
|
|
|
**Need Help?** Check the [root troubleshooting section](../README.md#troubleshooting) or backend documentation for API-related issues.
|