Merge branch 'release/2.0'
This commit is contained in:
@@ -8,7 +8,7 @@ import { TabsPage } from '../pages/tabs/tabs';
|
||||
@Component({
|
||||
templateUrl: 'app.html'
|
||||
})
|
||||
export class Urge {
|
||||
export class Urnings {
|
||||
rootPage: any = TabsPage;
|
||||
|
||||
constructor(platform: Platform, statusBar: StatusBar, splashScreen: SplashScreen) {
|
||||
|
||||
@@ -3,37 +3,39 @@ import { BrowserModule } from '@angular/platform-browser';
|
||||
import { HttpModule } from '@angular/http';
|
||||
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
|
||||
import { IonicSwipeAllModule } from 'ionic-swipe-all';
|
||||
import { Urge } from './app.component';
|
||||
import { Urnings } from './app.component';
|
||||
|
||||
import { ChatPage } from '../pages/chat/chat';
|
||||
import { CruisePage } from '../pages/cruise/cruise';
|
||||
import { CruisesPage } from '../pages/cruises/cruises';
|
||||
import { GridPage } from '../pages/grid/grid';
|
||||
import { InformationPage } from '../pages/information/information';
|
||||
import { LightboxPage } from '../pages/lightbox/lightbox';
|
||||
import { MessagesPage } from '../pages/messages/messages';
|
||||
import { ProfilePage } from '../pages/profile/profile';
|
||||
import { TabsPage } from '../pages/tabs/tabs';
|
||||
import { TellYourStoryPage } from '../pages/tell/tell';
|
||||
import { UsersPage } from '../pages/users/users';
|
||||
|
||||
import { StatusBar } from '@ionic-native/status-bar';
|
||||
import { SplashScreen } from '@ionic-native/splash-screen';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
Urge,
|
||||
Urnings,
|
||||
ChatPage,
|
||||
CruisePage,
|
||||
CruisesPage,
|
||||
InformationPage,
|
||||
GridPage,
|
||||
LightboxPage,
|
||||
MessagesPage,
|
||||
ProfilePage,
|
||||
TabsPage
|
||||
TabsPage,
|
||||
TellYourStoryPage,
|
||||
UsersPage
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
HttpModule,
|
||||
IonicSwipeAllModule,
|
||||
IonicModule.forRoot(Urge, {
|
||||
IonicModule.forRoot(Urnings, {
|
||||
iconMode: 'ios',
|
||||
modalEnter: 'modal-slide-in',
|
||||
modalLeave: 'modal-slide-out',
|
||||
@@ -43,15 +45,16 @@ import { SplashScreen } from '@ionic-native/splash-screen';
|
||||
],
|
||||
bootstrap: [IonicApp],
|
||||
entryComponents: [
|
||||
Urge,
|
||||
Urnings,
|
||||
ChatPage,
|
||||
CruisePage,
|
||||
CruisesPage,
|
||||
InformationPage,
|
||||
GridPage,
|
||||
LightboxPage,
|
||||
MessagesPage,
|
||||
ProfilePage,
|
||||
TabsPage
|
||||
TabsPage,
|
||||
TellYourStoryPage,
|
||||
UsersPage
|
||||
],
|
||||
providers: [
|
||||
StatusBar,
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
// for the .md, .ios, or .wp mode classes. The mode class is
|
||||
// automatically applied to the <body> element in the app.
|
||||
|
||||
body {
|
||||
font-family: 'PT Sans', sans-serif;
|
||||
}
|
||||
|
||||
ion-toolbar {
|
||||
color: #fff;
|
||||
|
||||
@@ -24,7 +28,7 @@ ion-toolbar {
|
||||
|
||||
.bar-button,
|
||||
.toolbar-title {
|
||||
color: #9e9ea8;
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +63,7 @@ ion-title {
|
||||
.tab-button {
|
||||
|
||||
.tab-button-icon {
|
||||
color: #9e9ea8;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
&[aria-selected=true] {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<html lang="en" dir="ltr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Urge</title>
|
||||
<title>Urnings</title>
|
||||
<meta name="viewport" content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="format-detection" content="telephone=no">
|
||||
<meta name="msapplication-tap-highlight" content="no">
|
||||
@@ -17,6 +17,7 @@
|
||||
<link rel="apple-touch-startup-image" sizes="750x1334" href="assets/imgs/launch-screen-750x1334.png">
|
||||
<link rel="apple-touch-startup-image" sizes="1125x2436" href="assets/imgs/launch-screen-1125x2436.png">
|
||||
<link rel="apple-touch-startup-image" sizes="1242x2208" href="assets/imgs/launch-screen-1242x2208.png">
|
||||
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<meta name="apple-mobile-web-app-title" content="Urge">
|
||||
@@ -33,6 +34,7 @@
|
||||
}
|
||||
</script>-->
|
||||
|
||||
<link href="https://fonts.googleapis.com/css?family=PT+Sans" rel="stylesheet">
|
||||
<link href="build/main.css" rel="stylesheet">
|
||||
|
||||
</head>
|
||||
|
||||
@@ -5,14 +5,7 @@
|
||||
<ion-icon name="arrow-back"></ion-icon>
|
||||
</button>
|
||||
</ion-buttons>
|
||||
|
||||
<ion-title><img class="title-profile-avatar" [src]="'https://appsby.fitz.guru/urge/' + this.profile.details.pic.thumb" height="24" width="24"> {{this.profile.details.name}}</ion-title>
|
||||
|
||||
<!--ion-buttons right>
|
||||
<button ion-button icon-only>
|
||||
<ion-icon name="more"></ion-icon>
|
||||
</button>
|
||||
</ion-buttons-->
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
|
||||
@@ -12,40 +12,17 @@ page-chat {
|
||||
.message-bubble {
|
||||
background-color: #fdb315;
|
||||
border-radius: 0.5rem;
|
||||
font-family: 'Helvetica Neue', HelveticaNeue, Helvetica, Arial, sans-serif;
|
||||
line-height: 1.5;
|
||||
margin: 1rem 1rem 2.5rem auto;
|
||||
max-width: 75%;
|
||||
overflow: visible;
|
||||
padding: 0.75rem;
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
border: 0.625em solid transparent;
|
||||
border-bottom: 0;
|
||||
border-right: 0;
|
||||
border-top-color: #fdb315;
|
||||
bottom: 0;
|
||||
content: '';
|
||||
height: 0;
|
||||
right: 2rem;
|
||||
margin-bottom: -0.6em;
|
||||
margin-left: -0.312em;
|
||||
position: absolute;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
&.is-user {
|
||||
background-color: #6fbedf;
|
||||
margin: 1rem auto 2.5rem 1rem;
|
||||
|
||||
&::after {
|
||||
border: 0.625em solid transparent;
|
||||
border-bottom: 0;
|
||||
border-left: 0;
|
||||
border-top-color: #6fbedf;
|
||||
right: auto;
|
||||
margin-right: -0.312em;
|
||||
left: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.item-inner {
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
<ion-content no-padding [style.backgroundImage]="getBackground(this.cruise.pic)" (press)="showLightbox($event, this.cruise.pic.detail)">
|
||||
<ion-toolbar>
|
||||
<ion-buttons left>
|
||||
<button ion-button icon-only (tap)="closeCruise($event)">
|
||||
<ion-icon name="arrow-back"></ion-icon>
|
||||
</button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
<div id="detail-overlay" class="details">
|
||||
<ion-grid>
|
||||
<ion-row nowrap align-items-center justify-content-between swipeAll (swipedown)="closeCruiseDetails($event)" (swipeup)="openCruiseDetails($event)" (click)="toggleCruiseDetails($event)">
|
||||
<ion-col col-8>
|
||||
<h2 class="placename">{{this.cruise.name}}</h2>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
<ion-row class="location" *ngIf="this.cruise.location">
|
||||
<ion-col col-4>Location</ion-col>
|
||||
<ion-col col-8 [innerHTML]="getFormattedCruiseAddress(this.cruise.location)"></ion-col>
|
||||
</ion-row>
|
||||
<ion-row class="text" *ngIf="this.cruise.text">
|
||||
<ion-col col-12 [innerHTML]="this.cruise.text"></ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
</div>
|
||||
</ion-content>
|
||||
@@ -1,47 +0,0 @@
|
||||
page-cruise {
|
||||
|
||||
ion-content {
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
.scroll-content {
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
ion-toolbar {
|
||||
|
||||
.toolbar-background {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.bar-button {
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
.details {
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
bottom: 0;
|
||||
height: 60px;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
transition: all 250ms 125ms ease-in-out;
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.location {
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
&.open {
|
||||
height: 100%;
|
||||
overflow-y: scroll;
|
||||
padding-top: 35px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { DomSanitizer } from '@angular/platform-browser';
|
||||
import { NavController, NavParams } from 'ionic-angular';
|
||||
|
||||
import { LightboxPage } from '../lightbox/lightbox';
|
||||
|
||||
@Component({
|
||||
selector: 'page-cruise',
|
||||
templateUrl: 'cruise.html'
|
||||
})
|
||||
export class CruisePage {
|
||||
|
||||
detailsOpen: boolean = false;
|
||||
cruise: any;
|
||||
tabNavEl: any;
|
||||
|
||||
constructor(public navCtrl: NavController, public navParams: NavParams, private _sanitizer: DomSanitizer) {
|
||||
this.cruise = navParams.get('cruise');
|
||||
this.tabNavEl = document.querySelector('#tab-nav .tabbar');
|
||||
}
|
||||
|
||||
ionViewWillEnter() {
|
||||
this.tabNavEl.style.display = 'none';
|
||||
}
|
||||
|
||||
closeCruise(event) {
|
||||
this.navCtrl.pop();
|
||||
}
|
||||
|
||||
closeCruiseDetails(event) {
|
||||
if (this.detailsOpen) {
|
||||
this.detailsOpen = false;
|
||||
document.getElementById('detail-overlay').classList.remove('open');
|
||||
}
|
||||
}
|
||||
|
||||
getBackground(images) {
|
||||
return this._sanitizer.bypassSecurityTrustStyle('url(https://appsby.fitz.guru/urge/' + images.detail + ')');
|
||||
}
|
||||
|
||||
getFormattedCruiseAddress(location) {
|
||||
var address = '';
|
||||
if (location && location.address) {
|
||||
address += location.address.street1 ? location.address.street1 + '<br>' : '';
|
||||
address += location.address.street2 ? location.address.street2 + '<br>' : '';
|
||||
address += location.address.locality ? location.address.locality + ', ' : '';
|
||||
address += location.address.region ? location.address.region + ' ' : '';
|
||||
address += location.address.postal ? location.address.postal + '<br>' : '';
|
||||
address += location.address.country ? location.address.country : '';
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
markFavorite(event, cruise) {
|
||||
console.debug('favorite cruise', { event: event, profile: cruise });
|
||||
}
|
||||
|
||||
openCruiseDetails(event) {
|
||||
if (!this.detailsOpen) {
|
||||
this.detailsOpen = true;
|
||||
document.getElementById('detail-overlay').classList.add('open');
|
||||
}
|
||||
}
|
||||
|
||||
showLightbox(event, image) {
|
||||
if (event.target.classList.contains('scroll-content')) {
|
||||
this.navCtrl.push(LightboxPage, {
|
||||
image: image
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
toggleCruiseDetails(event) {
|
||||
if (!this.detailsOpen) {
|
||||
this.openCruiseDetails(event);
|
||||
} else {
|
||||
this.closeCruiseDetails(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
<ion-content no-padding>
|
||||
<ion-grid no-padding>
|
||||
<ion-row align-items-stretch>
|
||||
<ion-col col-6 class="cruise" *ngFor="let current of cruises" (tap)="profileTapped($event, current)" [style.backgroundImage]="getBackgroundThumbnail(current.pic)">
|
||||
<span class="placename" [ngClass]="{ 'online': (current.messages?.length > 0) }">{{current.name}}</span>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
</ion-content>
|
||||
@@ -1,38 +0,0 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { DomSanitizer } from '@angular/platform-browser';
|
||||
import { NavController } from 'ionic-angular';
|
||||
|
||||
import { CruiseService } from '../../services/cruises';
|
||||
import { CruisePage } from '../cruise/cruise';
|
||||
|
||||
@Component({
|
||||
selector: 'page-cruises',
|
||||
templateUrl: 'cruises.html',
|
||||
providers: [ CruiseService ]
|
||||
})
|
||||
export class CruisesPage {
|
||||
|
||||
cruises: any;
|
||||
tabNavEl: any;
|
||||
|
||||
constructor(public navCtrl: NavController, public cruiseService: CruiseService, private _sanitizer: DomSanitizer) {
|
||||
cruiseService.load().then((data) => {
|
||||
this.cruises = data;
|
||||
});
|
||||
this.tabNavEl = document.querySelector('#tab-nav .tabbar');
|
||||
}
|
||||
|
||||
ionViewWillEnter() {
|
||||
this.tabNavEl.style.display = 'flex';
|
||||
}
|
||||
|
||||
getBackgroundThumbnail(images) {
|
||||
return this._sanitizer.bypassSecurityTrustStyle('url(https://appsby.fitz.guru/urge/' + images.thumb + ')');
|
||||
}
|
||||
|
||||
profileTapped(event, cruise) {
|
||||
this.navCtrl.push(CruisePage, {
|
||||
cruise: cruise
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,9 @@
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Urnings</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content no-padding>
|
||||
<ion-grid no-padding>
|
||||
<ion-row align-items-stretch>
|
||||
|
||||
@@ -1,6 +1,21 @@
|
||||
page-grid {
|
||||
|
||||
ion-col {
|
||||
ion-toolbar {
|
||||
|
||||
.toolbar-title {
|
||||
color: #ffffff;
|
||||
font-size: 2.42em;
|
||||
font-weight: 700;
|
||||
line-height: 1.29;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.grid {
|
||||
|
||||
.row {
|
||||
|
||||
.col {
|
||||
|
||||
&.profile {
|
||||
background-size: cover;
|
||||
@@ -13,14 +28,14 @@ page-grid {
|
||||
background-size: cover;
|
||||
bottom: 0.25rem;
|
||||
box-sizing: border-box;
|
||||
color: #acacac;
|
||||
color: #ffffff;
|
||||
display: inline-block;
|
||||
left: 0.5rem;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
right: 0.25rem;
|
||||
text-overflow: ellipsis;
|
||||
text-shadow: rgba(0, 0, 0, 1);
|
||||
text-shadow: 0 0 3px rgba(0, 0, 0, 1);
|
||||
white-space: nowrap;
|
||||
|
||||
&::before {
|
||||
@@ -39,8 +54,10 @@ page-grid {
|
||||
&.online {
|
||||
|
||||
&::before {
|
||||
background-color: #00FF00;
|
||||
border-color: #00FF00;
|
||||
background-color: #00ff00;
|
||||
border-color: #00ff00;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { NavController } from 'ionic-angular';
|
||||
import { ChatPage } from '../chat/chat';
|
||||
import { ProfileService } from '../../services/profiles';
|
||||
import { ProfilePage } from '../profile/profile';
|
||||
import { TellYourStoryPage } from '../tell/tell';
|
||||
|
||||
@Component({
|
||||
selector: 'page-grid',
|
||||
@@ -27,6 +28,10 @@ export class GridPage {
|
||||
this.tabNavEl.style.display = 'flex';
|
||||
}
|
||||
|
||||
doTellStory() {
|
||||
this.navCtrl.push(TellYourStoryPage);
|
||||
}
|
||||
|
||||
getBackgroundThumbnail(pics) {
|
||||
return this._sanitizer.bypassSecurityTrustStyle('url(https://appsby.fitz.guru/urge/' + pics.thumb + ')');
|
||||
}
|
||||
@@ -41,7 +46,7 @@ export class GridPage {
|
||||
|
||||
profileTapped(event, profile) {
|
||||
this.navCtrl.push(ProfilePage, {
|
||||
profile: profile
|
||||
profile: profile,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
20
src/pages/information/information.html
Normal file
20
src/pages/information/information.html
Normal file
@@ -0,0 +1,20 @@
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-buttons right>
|
||||
<button ion-button icon-only (tap)="close($event)">
|
||||
<ion-icon name="close"></ion-icon>
|
||||
</button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content padding>
|
||||
<div class="content-box" padding margin>
|
||||
<h3>About this Project</h3>
|
||||
<div class="info-blurb">
|
||||
<p>The app was designed by Nicholas Pfosi and developed by Michael Fitzpatrick, modeled after the popular gay dating app Grindr.</p>
|
||||
<p>Presenting these stories in this form, which is the conduit through which much participation in dating occurs, served multiple purposes. First, it educated the viewer who may not have used Grindr before, how it functions and how it is different from other apps such as Tinder, whereby matching with a person is a prerequisite for conversation. Second, it makes the scope of the project flexible, allowing for the submission of stories from the audience to be slotted into an expandable presentation.</p>
|
||||
<p>Please direct any questions or concerns to Nicholas Pfosi at npfosi@gmail.com</p>
|
||||
</div>
|
||||
</div>
|
||||
</ion-content>
|
||||
9
src/pages/information/information.scss
Normal file
9
src/pages/information/information.scss
Normal file
@@ -0,0 +1,9 @@
|
||||
page-information {
|
||||
|
||||
.content-box {
|
||||
background-color: #ffffff;
|
||||
color: #000000;
|
||||
font-family: 'Helvetica Neue', HelveticaNeue, Helvetica, Arial, sans-serif;
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
23
src/pages/information/information.ts
Normal file
23
src/pages/information/information.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { NavController } from 'ionic-angular';
|
||||
|
||||
@Component({
|
||||
selector: 'page-information',
|
||||
templateUrl: 'information.html',
|
||||
})
|
||||
export class InformationPage {
|
||||
|
||||
tabNavEl: any;
|
||||
|
||||
constructor(public navCtrl: NavController) {
|
||||
this.tabNavEl = document.querySelector('#tab-nav .tabbar');
|
||||
}
|
||||
|
||||
ionViewWillEnter() {
|
||||
this.tabNavEl.style.display = 'none';
|
||||
}
|
||||
|
||||
close(event) {
|
||||
this.navCtrl.pop();
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-buttons left>
|
||||
<ion-buttons right>
|
||||
<button ion-button icon-only (tap)="close($event)">
|
||||
<ion-icon name="arrow-back"></ion-icon>
|
||||
<ion-icon name="close"></ion-icon>
|
||||
</button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
|
||||
@@ -1,23 +1,14 @@
|
||||
<ion-header no-border>
|
||||
<ion-row>
|
||||
<ion-col text-center>
|
||||
<button ion-button clear small>
|
||||
Messages
|
||||
</button>
|
||||
</ion-col>
|
||||
<!--ion-col text-center>
|
||||
<button ion-button clear small>
|
||||
Taps
|
||||
</button>
|
||||
</ion-col-->
|
||||
</ion-row>
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Urnings</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content no-padding>
|
||||
<ion-list>
|
||||
<ng-container *ngFor="let profile of profiles">
|
||||
<ion-item no-padding *ngIf="profile.messages?.length > 0">
|
||||
<ion-thumbnail item-start (tap)="profilePictureTapped($event, profile)">
|
||||
<ion-thumbnail padding-left item-start (tap)="profilePictureTapped($event, profile)">
|
||||
<img [src]="'https://appsby.fitz.guru/urge/' + profile.details.pic.thumb">
|
||||
</ion-thumbnail>
|
||||
<ion-grid (tap)="interviewTapped($event, profile)">
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
page-messages {
|
||||
|
||||
ion-toolbar {
|
||||
|
||||
.toolbar-title {
|
||||
color: #ffffff;
|
||||
font-size: 2.42em;
|
||||
font-weight: 700;
|
||||
line-height: 1.29;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
ion-header {
|
||||
|
||||
.button {
|
||||
@@ -8,10 +19,12 @@ page-messages {
|
||||
}
|
||||
|
||||
.col {
|
||||
color: #acacac;
|
||||
color: #ffffff;
|
||||
font-family: 'Helvetica Neue', HelveticaNeue, Helvetica, Arial, sans-serif;
|
||||
line-height: 1.5;
|
||||
|
||||
&.username {
|
||||
font-size: 0.8em;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
&.timestamp {
|
||||
@@ -19,6 +32,10 @@ page-messages {
|
||||
font-style: italic;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.latest-message {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
}
|
||||
|
||||
.list {
|
||||
|
||||
@@ -1,81 +1,27 @@
|
||||
<ion-content no-padding [style.backgroundImage]="getBackground(profile.details.pic)" (press)="showLightbox($event, profile.details.pic.detail)">
|
||||
<ion-toolbar>
|
||||
<ion-content no-padding [style.backgroundImage]="getBackground(profile.details.pic)" (press)="showLightbox($event, profile.details.pic.detail)" on-swipe-left="nextProfile($event)" on-swipe-right="previousProfile($event)">
|
||||
<ion-toolbar class="profile-toolbar">
|
||||
<ion-buttons left>
|
||||
<button ion-button icon-only (tap)="closeProfile($event)">
|
||||
<ion-icon name="arrow-back"></ion-icon>
|
||||
</button>
|
||||
</ion-buttons>
|
||||
|
||||
<!--ion-buttons right>
|
||||
<button ion-button icon-only>
|
||||
<ion-icon name="cog"></ion-icon>
|
||||
</button>
|
||||
</ion-buttons-->
|
||||
<ion-title>{{this.profile.details.name}}</ion-title>
|
||||
</ion-toolbar>
|
||||
|
||||
<button ion-button icon-only clear large (tap)="openChat($event, this.profile)" class="button-chat">
|
||||
<ion-icon name="ios-chatboxes"></ion-icon>
|
||||
</button>
|
||||
|
||||
<div id="detail-overlay" class="details">
|
||||
<ion-grid>
|
||||
<ion-row nowrap align-items-center justify-content-between swipeAll (swipedown)="closeProfileDetails($event)" (swipeup)="openProfileDetails($event)" (click)="toggleProfileDetails($event)">
|
||||
<ion-col col-8>
|
||||
<h2 class="display-name">{{this.profile.details.name}}</h2>
|
||||
</ion-col>
|
||||
<ion-col col-4 class="actions" *ngIf="this.profile.messages?.length > 0">
|
||||
<button ion-button icon-only clear (tap)="openChat($event, this.profile)">
|
||||
<ion-icon name='ios-chatboxes-outline'></ion-icon>
|
||||
</button>
|
||||
<ion-row nowrap align-items-center justify-content-between>
|
||||
<ion-col col-12 text-center (click)="toggleProfileDetails($event)" class="detail-toggle">
|
||||
<ion-icon name="arrow-down"></ion-icon>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
<ion-row class="about" *ngIf="this.profile.details.about">
|
||||
<ion-col col-12 [innerHTML]="this.profile.details.about"></ion-col>
|
||||
</ion-row>
|
||||
<ion-row class="height" *ngIf="this.profile.details.height">
|
||||
<ion-col col-4>Height</ion-col>
|
||||
<ion-col col-8>{{this.profile.details.height}}</ion-col>
|
||||
</ion-row>
|
||||
<ion-row class="weight" *ngIf="this.profile.details.weight">
|
||||
<ion-col col-4>Weight</ion-col>
|
||||
<ion-col col-8>{{this.profile.details.weight}}</ion-col>
|
||||
</ion-row>
|
||||
<ion-row class="ethnicity" *ngIf="this.profile.details.ethnicity != 'dns'">
|
||||
<ion-col col-4>Ethnicity</ion-col>
|
||||
<ion-col col-8>{{this.profile.details.ethnicity}}</ion-col>
|
||||
</ion-row>
|
||||
<ion-row class="body" *ngIf="this.profile.details.body != 'dns'">
|
||||
<ion-col col-4>Body Type</ion-col>
|
||||
<ion-col col-8>{{this.profile.details.body}}</ion-col>
|
||||
</ion-row>
|
||||
<ion-row class="gender" *ngIf="this.profile.details.gender">
|
||||
<ion-col col-4>Gender</ion-col>
|
||||
<ion-col col-8>{{this.profile.details.gender}}</ion-col>
|
||||
</ion-row>
|
||||
<ion-row class="pronouns" *ngIf="this.profile.details.pronouns">
|
||||
<ion-col col-4>Pronouns</ion-col>
|
||||
<ion-col col-8>{{this.profile.details.pronouns}}</ion-col>
|
||||
</ion-row>
|
||||
<ion-row class="tribes" *ngIf="this.profile.details.tribe?.length > 0">
|
||||
<ion-col col-4>Tribes</ion-col>
|
||||
<ion-col col-8><span *ng>{{this.profile.details.tribe}}</span></ion-col>
|
||||
</ion-row>
|
||||
<ion-row class="position" *ngIf="this.profile.details.position != 'dns'">
|
||||
<ion-col col-4>Position</ion-col>
|
||||
<ion-col col-8>{{this.profile.details.position}}</ion-col>
|
||||
</ion-row>
|
||||
<ion-row class="relationship" *ngIf="this.profile.details.relationship != 'dns'">
|
||||
<ion-col col-4>Relationship</ion-col>
|
||||
<ion-col col-8>{{this.profile.details.relationship}}</ion-col>
|
||||
</ion-row>
|
||||
<ion-row class="looking" *ngIf="this.profile.details.looking?.length > 0">
|
||||
<ion-col col-4>I'm Looking For</ion-col>
|
||||
<ion-col col-8><span *ng>{{this.profile.details.looking}}</span></ion-col>
|
||||
</ion-row>
|
||||
<ion-row class="status" *ngIf="this.profile.details.status != 'dns'">
|
||||
<ion-col col-4>HIV Status</ion-col>
|
||||
<ion-col col-8>{{this.profile.details.status}}</ion-col>
|
||||
</ion-row>
|
||||
<ion-row class="tested" *ngIf="this.profile.details.tested">
|
||||
<ion-col col-4>Last Tested</ion-col>
|
||||
<ion-col col-8>{{this.profile.details.tested}}</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
</div>
|
||||
</ion-content>
|
||||
|
||||
@@ -11,18 +11,38 @@ page-profile {
|
||||
}
|
||||
|
||||
ion-toolbar {
|
||||
border-bottom: 1px solid #ffffff;
|
||||
transition: opacity 250ms 125ms ease-in-out;
|
||||
|
||||
.toolbar-background {
|
||||
background-color: transparent;
|
||||
&.hidden {
|
||||
opacity: 0;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.bar-button {
|
||||
.toolbar-background {
|
||||
background-color: rgba(0, 0, 0, 1);
|
||||
}
|
||||
|
||||
.bar-button,
|
||||
.toolbar-title {
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
.button-chat {
|
||||
bottom: 3rem;
|
||||
color: #fdb315;
|
||||
position: absolute;
|
||||
right: 1.5rem;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.detail-toggle {
|
||||
font-size: 2.5em;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.details {
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
bottom: 0;
|
||||
height: 60px;
|
||||
left: 0;
|
||||
@@ -30,14 +50,15 @@ page-profile {
|
||||
right: 0;
|
||||
transition: all 250ms 125ms ease-in-out;
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
&.open {
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
height: 100%;
|
||||
overflow-y: scroll;
|
||||
padding-top: 35px;
|
||||
}
|
||||
|
||||
.about {
|
||||
font-family: 'Helvetica Neue', HelveticaNeue, Helvetica, Arial, sans-serif;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.actions {
|
||||
|
||||
@@ -4,18 +4,21 @@ import { NavController, NavParams } from 'ionic-angular';
|
||||
|
||||
import { ChatPage } from '../chat/chat';
|
||||
import { LightboxPage } from '../lightbox/lightbox';
|
||||
import { ProfileService } from '../../services/profiles';
|
||||
|
||||
@Component({
|
||||
selector: 'page-profile',
|
||||
templateUrl: 'profile.html'
|
||||
templateUrl: 'profile.html',
|
||||
providers: [ ProfileService ]
|
||||
})
|
||||
|
||||
export class ProfilePage {
|
||||
|
||||
detailsOpen: boolean = false;
|
||||
profile: any;
|
||||
tabNavEl: any;
|
||||
|
||||
constructor(public navCtrl: NavController, public navParams: NavParams, private _sanitizer: DomSanitizer) {
|
||||
constructor(public navCtrl: NavController, public navParams: NavParams, public profileService: ProfileService, private _sanitizer: DomSanitizer) {
|
||||
this.profile = navParams.get('profile');
|
||||
this.tabNavEl = document.querySelector('#tab-nav .tabbar');
|
||||
}
|
||||
@@ -31,6 +34,7 @@ export class ProfilePage {
|
||||
closeProfileDetails(event) {
|
||||
if (this.detailsOpen) {
|
||||
this.detailsOpen = false;
|
||||
document.querySelector('.profile-toolbar').classList.remove('hidden');
|
||||
document.getElementById('detail-overlay').classList.remove('open');
|
||||
}
|
||||
}
|
||||
@@ -43,6 +47,11 @@ export class ProfilePage {
|
||||
console.debug('favorite profile', { event: event, profile: profile });
|
||||
}
|
||||
|
||||
nextProfile(event) {
|
||||
this.profile = this.profileService.getNextProfile(this.profile._id);
|
||||
this.navCtrl.setRoot(this.navCtrl.getActive().component);
|
||||
}
|
||||
|
||||
openChat(event, profile) {
|
||||
this.navCtrl.push(ChatPage, {
|
||||
profile: profile
|
||||
@@ -52,10 +61,16 @@ export class ProfilePage {
|
||||
openProfileDetails(event) {
|
||||
if (!this.detailsOpen) {
|
||||
this.detailsOpen = true;
|
||||
document.querySelector('.profile-toolbar').classList.add('hidden');
|
||||
document.getElementById('detail-overlay').classList.add('open');
|
||||
}
|
||||
}
|
||||
|
||||
previousProfile(event) {
|
||||
this.profile = this.profileService.getPreviousProfile(this.profile._id);
|
||||
this.navCtrl.setRoot(this.navCtrl.getActive().component);
|
||||
}
|
||||
|
||||
showLightbox(event, image) {
|
||||
if (event.target.classList.contains('scroll-content')) {
|
||||
this.navCtrl.push(LightboxPage, {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<ion-tabs id="tab-nav" selectedIndex="0">
|
||||
<ion-tab [root]="tab1Root" tabIcon="contacts"></ion-tab>
|
||||
<ion-tab [root]="tab2Root" tabIcon="boat"></ion-tab>
|
||||
<ion-tab [root]="tab2Root" tabIcon="compass"></ion-tab>
|
||||
<ion-tab [root]="tab3Root" tabIcon="chatboxes"></ion-tab>
|
||||
<ion-tab [root]="tab4Root" tabIcon="information-circle"></ion-tab>
|
||||
</ion-tabs>
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
import { GridPage } from '../grid/grid';
|
||||
import { CruisesPage } from '../cruises/cruises';
|
||||
import { InformationPage } from '../information/information';
|
||||
import { MessagesPage } from '../messages/messages';
|
||||
import { UsersPage } from '../users/users';
|
||||
|
||||
@Component({
|
||||
templateUrl: 'tabs.html'
|
||||
@@ -10,8 +11,9 @@ import { MessagesPage } from '../messages/messages';
|
||||
export class TabsPage {
|
||||
|
||||
tab1Root = GridPage;
|
||||
tab2Root = CruisesPage;
|
||||
tab2Root = UsersPage;
|
||||
tab3Root = MessagesPage;
|
||||
tab4Root = InformationPage;
|
||||
|
||||
constructor() {
|
||||
|
||||
|
||||
12
src/pages/tell/tell.html
Normal file
12
src/pages/tell/tell.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-buttons right>
|
||||
<button ion-button icon-only (tap)="close($event)">
|
||||
<ion-icon name="close"></ion-icon>
|
||||
</button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content>
|
||||
</ion-content>
|
||||
@@ -1,4 +1,4 @@
|
||||
page-cruises {
|
||||
page-tell-your-story {
|
||||
|
||||
ion-col {
|
||||
|
||||
26
src/pages/tell/tell.ts
Normal file
26
src/pages/tell/tell.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { NavController } from 'ionic-angular';
|
||||
|
||||
import { ProfileService } from '../../services/profiles';
|
||||
|
||||
@Component({
|
||||
selector: 'page-tell-your-story',
|
||||
templateUrl: 'tell.html',
|
||||
providers: [ ProfileService ]
|
||||
})
|
||||
export class TellYourStoryPage {
|
||||
|
||||
tabNavEl: any;
|
||||
|
||||
constructor(public navCtrl: NavController) {
|
||||
this.tabNavEl = document.querySelector('#tab-nav .tabbar');
|
||||
}
|
||||
|
||||
ionViewWillEnter() {
|
||||
this.tabNavEl.style.display = 'none';
|
||||
}
|
||||
|
||||
close(event) {
|
||||
this.navCtrl.pop();
|
||||
}
|
||||
}
|
||||
20
src/pages/users/users.html
Normal file
20
src/pages/users/users.html
Normal file
@@ -0,0 +1,20 @@
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Urnings</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content no-padding>
|
||||
<ion-grid no-padding>
|
||||
<ion-row align-items-stretch>
|
||||
<ion-col col-4 class="profile tell-your-story">
|
||||
<button ion-button clear large icon-only (tap)="doTellStory()">
|
||||
<ion-icon name="md-person-add"></ion-icon>
|
||||
</button>
|
||||
</ion-col>
|
||||
<ion-col col-4 class="profile" *ngFor="let current of profiles" (tap)="profileTapped($event, current)" (press)="profilePressed($event, current)" [style.backgroundImage]="getBackgroundThumbnail(current.details.pic)">
|
||||
<span class="username" [ngClass]="{ 'online': (current.messages?.length > 0) }">{{current.details.name}}</span>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
</ion-content>
|
||||
78
src/pages/users/users.scss
Normal file
78
src/pages/users/users.scss
Normal file
@@ -0,0 +1,78 @@
|
||||
page-users {
|
||||
|
||||
ion-toolbar {
|
||||
|
||||
.toolbar-title {
|
||||
color: #ffffff;
|
||||
font-size: 2.42em;
|
||||
font-weight: 700;
|
||||
line-height: 1.29;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.grid {
|
||||
|
||||
.row {
|
||||
|
||||
.col {
|
||||
|
||||
&.profile {
|
||||
background-size: cover;
|
||||
border: 1px solid #000000;
|
||||
box-sizing: border-box;
|
||||
padding: 0 0 33% !important;
|
||||
position: relative;
|
||||
|
||||
&.tell-your-story {
|
||||
position: relative;
|
||||
|
||||
button {
|
||||
color: #acacac;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate3d(-50%, -50%, 0);
|
||||
}
|
||||
}
|
||||
|
||||
.username {
|
||||
background-size: cover;
|
||||
bottom: 0.25rem;
|
||||
box-sizing: border-box;
|
||||
color: #ffffff;
|
||||
display: inline-block;
|
||||
left: 0.5rem;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
right: 0.25rem;
|
||||
text-overflow: ellipsis;
|
||||
text-shadow: 0 0 3px rgba(0, 0, 0, 1);
|
||||
white-space: nowrap;
|
||||
|
||||
&::before {
|
||||
border: 0.125rem solid #acacac;
|
||||
border-radius: 1rem;
|
||||
bottom: 0.125rem;
|
||||
content: '';
|
||||
display: inline-block;
|
||||
height: 0.8rem;
|
||||
margin-right: 0.5rem;
|
||||
position: relative;
|
||||
vertical-align: middle;
|
||||
width: 0.8rem;
|
||||
}
|
||||
|
||||
&.online {
|
||||
|
||||
&::before {
|
||||
background-color: #00ff00;
|
||||
border-color: #00ff00;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
52
src/pages/users/users.ts
Normal file
52
src/pages/users/users.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { DomSanitizer } from '@angular/platform-browser';
|
||||
import { NavController } from 'ionic-angular';
|
||||
|
||||
import { ChatPage } from '../chat/chat';
|
||||
import { ProfileService } from '../../services/profiles';
|
||||
import { ProfilePage } from '../profile/profile';
|
||||
import { TellYourStoryPage } from '../tell/tell';
|
||||
|
||||
@Component({
|
||||
selector: 'page-users',
|
||||
templateUrl: 'users.html',
|
||||
providers: [ ProfileService ]
|
||||
})
|
||||
export class UsersPage {
|
||||
|
||||
profiles: any;
|
||||
tabNavEl: any;
|
||||
|
||||
constructor(public navCtrl: NavController, public profileService: ProfileService, private _sanitizer: DomSanitizer) {
|
||||
profileService.loadSubmitted().then((data) => {
|
||||
this.profiles = data;
|
||||
});
|
||||
this.tabNavEl = document.querySelector('#tab-nav .tabbar');
|
||||
}
|
||||
|
||||
ionViewWillEnter() {
|
||||
this.tabNavEl.style.display = 'flex';
|
||||
}
|
||||
|
||||
doTellStory() {
|
||||
this.navCtrl.push(TellYourStoryPage);
|
||||
}
|
||||
|
||||
getBackgroundThumbnail(pics) {
|
||||
return this._sanitizer.bypassSecurityTrustStyle('url(https://appsby.fitz.guru/urge/' + pics.thumb + ')');
|
||||
}
|
||||
|
||||
profilePressed(event, profile) {
|
||||
if (profile.messages && profile.messages.length) {
|
||||
this.navCtrl.push(ChatPage, {
|
||||
profile: profile
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
profileTapped(event, profile) {
|
||||
this.navCtrl.push(ProfilePage, {
|
||||
profile: profile,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Http } from '@angular/http';
|
||||
import 'rxjs/add/operator/map';
|
||||
|
||||
@Injectable()
|
||||
export class CruiseService {
|
||||
|
||||
endpoint: string = 'assets/data/cruises.json';
|
||||
//endpoint: string = 'https://api.fitz.guru/urge/cruises';
|
||||
idMap: any;
|
||||
cruises: any;
|
||||
|
||||
constructor(private http: Http) {
|
||||
this.idMap = {};
|
||||
this.cruises = null;
|
||||
}
|
||||
|
||||
load() {
|
||||
if (this.cruises) {
|
||||
return Promise.resolve(this.cruises);
|
||||
}
|
||||
|
||||
return new Promise(resolve => {
|
||||
this.http.get(this.endpoint)
|
||||
.map(res => res.json())
|
||||
.subscribe(data => {
|
||||
this.cruises = data;
|
||||
this.cruises.reduce((map, cruise, i) => {
|
||||
map[cruise._id] = i;
|
||||
return map;
|
||||
}, this.idMap);
|
||||
resolve(this.cruises);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
getCruises() {
|
||||
return this.cruises;
|
||||
}
|
||||
|
||||
getCruiseById(id) {
|
||||
return this.cruises[this.idMap[id]];
|
||||
}
|
||||
}
|
||||
@@ -5,11 +5,14 @@ import 'rxjs/add/operator/map';
|
||||
@Injectable()
|
||||
export class ProfileService {
|
||||
|
||||
endpoint: string = 'https://api.fitz.guru/urge/profiles';
|
||||
endpoint: string = 'https://api.fitz.guru/urnings/profiles';
|
||||
fallback: string = 'assets/data/profiles.json';
|
||||
idMap: any;
|
||||
epSubmitted: string = '/submitted';
|
||||
epVerified: string = '/verified';
|
||||
idMap: any = { all: {}, submitted: {}, verified: {} };
|
||||
profiles: any;
|
||||
|
||||
|
||||
constructor(private http: Http) {
|
||||
this.idMap = {};
|
||||
this.profiles = null;
|
||||
@@ -21,27 +24,59 @@ export class ProfileService {
|
||||
}
|
||||
|
||||
return new Promise(resolve => {
|
||||
this.http.get(this.endpoint)
|
||||
this.doGetRequest(this.endpoint, resolve);
|
||||
});
|
||||
}
|
||||
|
||||
loadSubmitted() {
|
||||
if (this.profiles) {
|
||||
return Promise.resolve(this.profiles);
|
||||
}
|
||||
|
||||
return new Promise(resolve => {
|
||||
this.doGetRequest(this.endpoint + this.epSubmitted, resolve, 'submitted');
|
||||
});
|
||||
}
|
||||
|
||||
loadVerified() {
|
||||
if (this.profiles) {
|
||||
return Promise.resolve(this.profiles);
|
||||
}
|
||||
|
||||
return new Promise(resolve => {
|
||||
this.doGetRequest(this.endpoint + this.epVerified, resolve, 'verified');
|
||||
});
|
||||
}
|
||||
|
||||
doGetRequest(endpoint, resolve, type = 'all') {
|
||||
this.http.get(endpoint)
|
||||
.map(res => res.json())
|
||||
.subscribe(
|
||||
data => {
|
||||
this.profiles = data;
|
||||
this.profiles = {};
|
||||
this.profiles[type] = data;
|
||||
this.profiles.reduce((map, profile, i) => {
|
||||
map[profile._id] = i;
|
||||
return map;
|
||||
}, this.idMap);
|
||||
resolve(this.profiles);
|
||||
}, this.idMap[type]);
|
||||
resolve(this.profiles[type]);
|
||||
},
|
||||
error => {
|
||||
this.profiles = this.fallback;
|
||||
this.profiles.reduce((map, profile, i) => {
|
||||
map[profile._id] = i;
|
||||
return map;
|
||||
}, this.idMap);
|
||||
resolve(this.profiles);
|
||||
this.doGetRequest(this.fallback, resolve);
|
||||
}
|
||||
);
|
||||
});
|
||||
)
|
||||
}
|
||||
|
||||
getNextProfile(id, type) {
|
||||
var nextIdIndex = this.idMap[id] + 1;
|
||||
nextIdIndex = nextIdIndex >= this.profiles.length ? 0 : nextIdIndex;
|
||||
return this.profiles[nextIdIndex];
|
||||
}
|
||||
|
||||
getPreviousProfile(id, type) {
|
||||
var prevIdIndex = this.idMap[id] + 1;
|
||||
prevIdIndex = prevIdIndex < 0 ? (this.profiles.length - 1) : prevIdIndex;
|
||||
return this.profiles[prevIdIndex];
|
||||
}
|
||||
|
||||
getProfiles() {
|
||||
@@ -51,4 +86,12 @@ export class ProfileService {
|
||||
getProfileById(id) {
|
||||
return this.profiles[this.idMap[id]];
|
||||
}
|
||||
|
||||
getSubmittedProfiles() {
|
||||
|
||||
}
|
||||
|
||||
getVerifiedProfiles() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user