Initial Commit

This commit is contained in:
Fergal Moran
2016-08-02 20:51:10 +01:00
commit 6ff626a3d8
33 changed files with 4810 additions and 0 deletions

46
app/app.ts Normal file
View File

@@ -0,0 +1,46 @@
//import 'es6-shim';
import {Component} from '@angular/core';
import {ionicBootstrap, Platform} from 'ionic-angular';
import {StatusBar} from 'ionic-native';
import {HomePage} from './pages/home/home';
import {
FIREBASE_PROVIDERS, defaultFirebase,
AngularFire, firebaseAuthConfig, AuthProviders,
AuthMethods
} from 'angularfire2';
@Component({
template: '<ion-nav [root]="rootPage"></ion-nav>',
providers: [
FIREBASE_PROVIDERS,
// Initialize Firebase app
defaultFirebase({
apiKey: "AIzaSyBltKr00N9-KPzkGYut2tkZSk_TIiydZm8",
authDomain: "icebreaker-f5f20.firebaseapp.com",
databaseURL: "https://icebreaker-f5f20.firebaseio.com",
storageBucket: "icebreaker-f5f20.appspot.com",
}),
firebaseAuthConfig({
provider: AuthProviders.Password,
method: AuthMethods.Password,
remember: 'default',
scope: ['email']
})
]
})
export class MyApp {
rootPage: any = HomePage;
constructor(platform: Platform) {
platform.ready().then(() => {
// Okay, so the platform is ready and our plugins are available.
// Here you can do any higher level native things you might need.
StatusBar.styleDefault();
});
}
}
ionicBootstrap(MyApp);

18
app/lib/MomentDate.ts Normal file
View File

@@ -0,0 +1,18 @@
import {Pipe} from '@angular/core';
import * as moment from 'moment';
// Tell Angular2 we're creating a Pipe with TypeScript decorators
@Pipe({
name: 'MomentDate'
})
export class MomentDate {
// Transform is the new "return function(value, args)" in Angular 1.x
transform(value, args?) {
// see http://momentjs.com/docs/#/displaying/ for information
// on formatting the date using moment
return moment(value).format(args[0])
}
}

41
app/pages/home/home.html Normal file
View File

@@ -0,0 +1,41 @@
<ion-header>
<ion-navbar>
<ion-title>
Ice Breaker
</ion-title>
<ion-buttons end>
<button (click)="logoutClicked()">
<ion-icon name="contact"></ion-icon>
{{buttonTitle}}
</button>
</ion-buttons>
</ion-navbar>
</ion-header>
<ion-content class="home">
<ion-item>
<ion-row>
<ion-col width-100>
<button (click)="addNewItemClicked()">Add Item</button>
</ion-col>
</ion-row>
</ion-item>
<ion-card *ngFor="let item of textItems | async">
<ion-card-header>
{{item.title}}
</ion-card-header>
<ion-card-content>
{{item.description}} - {{ item.timestamp | MomentDate:"LLL"}}
</ion-card-content>
<ion-col offset-80>
<button (click)="deleteItemClicked(item)">Delete</button>
</ion-col>
</ion-card>
<ion-card *ngFor="let user of usersWithMessages | async">
<ion-card-header>
{{user.displayName}}
</ion-card-header>
<ion-card-content>
{{ (user.messages | async) | json}}
</ion-card-content>
</ion-card>
</ion-content>

3
app/pages/home/home.scss Normal file
View File

@@ -0,0 +1,3 @@
.home {
}

127
app/pages/home/home.ts Normal file
View File

@@ -0,0 +1,127 @@
import {Modal, NavController, Page} from 'ionic-angular';
import {Component, OnInit, Inject} from '@angular/core';
import {Observable} from 'rxjs/Observable';
import {LoginPage} from '../login/login'
import {NewItemModal} from '../item/newItem';
import {MomentDate} from '../../lib/MomentDate'
import 'rxjs';
import { AngularFire, AuthProviders, AuthMethods } from 'angularfire2';
@Page({
templateUrl: 'build/pages/home/home.html',
pipes: [MomentDate]
})
export class HomePage implements OnInit {
textItems: Observable<any[]>;
usersWithMessages: Observable<any[]>;
authInfo: any
displayName: any
buttonTitle = "LOGIN"
constructor(
public af: AngularFire,
public navCtrl: NavController) {
// dont do anything heavy here... do it in ngOnInit
}
ngOnInit() {
// subscribe to the auth object to check for the login status
// of the user, if logged in, save some user information and
// execute the firebase query...
// .. otherwise
// show the login modal page
this.af.auth.subscribe((data) => {
console.log("in auth subscribe", data)
if (data) {
this.af.auth.unsubscribe()
this.buttonTitle = "LOGOUT"
// if no user, then add it
this.addOrUpdateUser(data)
if (data.auth.providerData[0].providerId === "twitter.com") {
this.authInfo = data.auth.providerData[0]
this.displayName = data.auth.providerData[0].displayName
} else if (data.github) {
this.authInfo = data.github
//this.authInfo.displayName = data.github.displayName
} else {
this.authInfo = data.auth || {}
this.displayName = data.auth.providerData[0].email
}
this.textItems = this.af.database.list('/textItems')
//this.getMoreData()
} else {
this.buttonTitle = "LOGIN"
this.authInfo = null
this.displayLoginModal()
}
})
}
addOrUpdateUser(_authData) {
const itemObservable = this.af.database.object('/users/' + _authData.uid);
itemObservable.set({
"provider": _authData.auth.providerData[0].providerId,
"avatar": _authData.auth.photoURL || "MISSING",
"displayName": _authData.auth.providerData[0].displayName || _authData.auth.email,
})
}
getMoreData() {
this.usersWithMessages = this.af.list('/users').map((_users) => {
return _users.map((_user) => {
_user.messages = this.af.object("/userObjects/public-messages/" + _user.$key)
return _user
})
})
}
/**
* displays the login window
*/
displayLoginModal() {
let loginPage = Modal.create(LoginPage);
this.navCtrl.present(loginPage);
}
/**
* adds a new item to firebase /textItems
*
* pass in the auth information to the modal to associate the user with the newly
* created entry
*/
addNewItemClicked(_data) {
let newItemPage = Modal.create(NewItemModal, { "user": this.authInfo });
this.navCtrl.present(newItemPage);
}
deleteItemClicked(_data) {
this.af.database.object("/textItems/" + _data.$key).remove()
.then(() => { alert("success") })
.catch((_error) => { alert("Error") })
}
/**
* logs out the current user
*/
logoutClicked() {
if (this.authInfo && (this.authInfo.email || this.authInfo.providerId)) {
this.af.auth.logout();
this.authInfo = null
this.displayLoginModal()
} else {
this.displayLoginModal()
}
}
}

View File

@@ -0,0 +1,26 @@
<ion-navbar *navbar hideBackButton>
<ion-title>
Angular Fire Test App - New Item
</ion-title>
</ion-navbar>
<ion-content padding>
<form #modelData="ngForm" (ngSubmit)="addTheItem(modelData.value)">
<ion-item>
<ion-label>Title</ion-label>
<ion-input required type="text" ngControl="title"></ion-input>
</ion-item>
<ion-item>
<ion-label>Description</ion-label>
<ion-input required type="text" ngControl="description"></ion-input>
</ion-item>
<div padding>
<button block type="submit" [disabled]="!modelData.valid">Add New Item</button>
<button block (click)="cancelItem($event)">Cancel</button>
</div>
<div padding>
<p *ngIf="error" class="error">Error:&nbsp;{{ error.code }}</p>
</div>
</form>
</ion-content>

61
app/pages/item/newItem.ts Normal file
View File

@@ -0,0 +1,61 @@
import {Modal, NavController, Page, ViewController, NavParams} from 'ionic-angular';
import {Component, OnInit, Inject} from '@angular/core';
import { AngularFire } from 'angularfire2';
@Page({
templateUrl: 'build/pages/item/newItem.html'
})
export class NewItemModal {
error: any
/**
* even though this is a Modal, we can access the navParam data passed into the object
* when the object is created. This is how we access the user auth data
*/
constructor(
public af: AngularFire,
public viewCtrl: ViewController,
private _navParams: NavParams) {
console.log("initialize NewItemModal")
}
/**
* this will dismiss the modal page
*/
dismiss() {
this.viewCtrl.dismiss();
}
/**
* exits the modal with no new item added
*/
cancelItem(_event) {
_event.preventDefault();
this.dismiss()
}
/**
* adds the item to the path /textItems
*/
addTheItem(_data) {
var textItems = this.af.database.list('/textItems');
textItems.push({
"title": _data.title,
"description": _data.description,
// auth data from the navParam object...
"user": this._navParams.get("user").email,
"timestamp": (new Date()).getTime()
}).then((_data) => {
console.log(_data)
alert("Item Successfully Added")
this.dismiss()
}).catch((_error) => {
console.log(_error)
alert("Error Adding Item")
})
}
}

View File

@@ -0,0 +1,29 @@
<ion-navbar *navbar>
<ion-title>
Ice Breaker
</ion-title>
</ion-navbar>
<ion-content padding>
<h1>User Login</h1>
<form #loginCreds="ngForm">
<ion-item>
<ion-label>Email</ion-label>
<ion-input type="text" ngControl="email"></ion-input>
</ion-item>
<ion-item>
<ion-label>Password</ion-label>
<ion-input type="password" ngControl="password"></ion-input>
</ion-item>
<div padding>
<button block (click)="login(loginCreds.value, $event)">Login</button>
<button block (click)="registerUser(loginCreds.value, $event)">Create Account</button>
</div>
<div padding>
<button block (click)="registerUserWithFacebook(loginCreds.value, $event)">Facebook</button>
<button block (click)="registerUserWithTwitter(loginCreds.value, $event)">Twitter</button>
</div>
<div padding>
<p *ngIf="error" class="error">Error:&nbsp;{{ error.code }}</p>
</div>
</form>
</ion-content>

128
app/pages/login/login.ts Normal file
View File

@@ -0,0 +1,128 @@
import {Modal, NavController, Page, ViewController} from 'ionic-angular';
import {Component, OnInit, Inject} from '@angular/core';
import {AngularFire, AuthProviders, AuthMethods } from 'angularfire2';
@Page({
templateUrl: 'build/pages/login/login.html'
})
export class LoginPage {
error: any
constructor(public af: AngularFire,
public viewCtrl: ViewController) { }
/**
* this will dismiss the modal page
*/
dismiss() {
this.viewCtrl.dismiss();
}
/**
* this create in the user using the form credentials.
*
* we are preventing the default behavor of submitting
* the form
*
* @param _credentials {Object} the email and password from the form
* @param _event {Object} the event information from the form submit
*/
registerUser(_credentials, _event) {
_event.preventDefault();
this.af.auth.createUser(_credentials)
.then((user) => {
console.log(`Create User Success:`, user);
_credentials.created = true;
return this.login(_credentials, _event);
})
.catch(e => console.error(`Create User Failure:`, e));
}
registerUserWithFacebook(_credentials, _event) {
_event.preventDefault();
this.af.auth.login({
provider: AuthProviders.Facebook,
method: AuthMethods.Popup
}).then((value) => {
this.dismiss()
}).catch((error) => {
this.error = error
console.log(error)
});
}
registerUserWithTwitter(_credentials, _event) {
_event.preventDefault();
this.af.auth.login({
provider: AuthProviders.Twitter,
method: AuthMethods.Redirect
}).then((authData) => {
console.log(authData)
// already has user... need better info??
if (!authData) {
this.dismiss()
}
const itemObservable = this.af.database.object('/users/' + authData.uid);
itemObservable.set({
"provider": authData.auth.providerData[0].providerId,
"avatar": authData.auth.photoURL || "MISSING",
"displayName": authData.auth.providerData[0].displayName || authData.auth.email,
})
}).then((value) => {
this.dismiss()
}).catch((error) => {
this.error = error
console.log(error)
});
}
/**
* this logs in the user using the form credentials.
*
* if the user is a new user, then we need to create the user AFTER
* we have successfully logged in
*
* @param _credentials {Object} the email and password from the form
* @param _event {Object} the event information from the form submit
*/
login(credentials, _event) {
_event.preventDefault();
// if this was called from the register user, the check if we
// need to create the user object or not
let addUser = credentials.created
credentials.created = null;
// login usig the email/password auth provider
this.af.auth.login(credentials, {
provider: AuthProviders.Password,
method: AuthMethods.Password
}).then((authData) => {
console.log(authData)
if (addUser) {
const itemObservable = this.af.database.object('/users/' + authData.uid);
itemObservable.set({
"provider": authData.auth.providerData[0].providerId,
"avatar": authData.auth.photoURL || "MISSING",
"displayName": authData.auth.providerData[0].displayName || authData.auth.email,
})
} else {
this.dismiss()
}
}).then((value) => {
this.dismiss()
}).catch((error) => {
this.error = error
console.log(error)
});
}
}

10
app/theme/app.core.scss Normal file
View File

@@ -0,0 +1,10 @@
// http://ionicframework.com/docs/v2/theming/
// App Shared Imports
// --------------------------------------------------
// These are the imports which make up the design of this app.
// By default each design mode includes these shared imports.
// App Shared Sass variables belong in app.variables.scss.
@import '../pages/home/home';

31
app/theme/app.ios.scss Normal file
View File

@@ -0,0 +1,31 @@
// http://ionicframework.com/docs/v2/theming/
// App Shared Variables
// --------------------------------------------------
// Shared Sass variables go in the app.variables.scss file
@import 'app.variables';
// App iOS Variables
// --------------------------------------------------
// iOS only Sass variables can go here
// Ionic iOS Sass
// --------------------------------------------------
// Custom App variables must be declared before importing Ionic.
// Ionic will use its default values when a custom variable isn't provided.
@import 'ionic.ios';
// App Shared Sass
// --------------------------------------------------
// All Sass files that make up this app goes into the app.core.scss file.
// For simpler CSS overrides, custom app CSS must come after Ionic's CSS.
@import 'app.core';
// App iOS Only Sass
// --------------------------------------------------
// CSS that should only apply to the iOS app

31
app/theme/app.md.scss Normal file
View File

@@ -0,0 +1,31 @@
// http://ionicframework.com/docs/v2/theming/
// App Shared Variables
// --------------------------------------------------
// Shared Sass variables go in the app.variables.scss file
@import 'app.variables';
// App Material Design Variables
// --------------------------------------------------
// Material Design only Sass variables can go here
// Ionic Material Design Sass
// --------------------------------------------------
// Custom App variables must be declared before importing Ionic.
// Ionic will use its default values when a custom variable isn't provided.
@import 'ionic.md';
// App Shared Sass
// --------------------------------------------------
// All Sass files that make up this app goes into the app.core.scss file.
// For simpler CSS overrides, custom app CSS must come after Ionic's CSS.
@import 'app.core';
// App Material Design Only Sass
// --------------------------------------------------
// CSS that should only apply to the Material Design app

View File

@@ -0,0 +1,35 @@
// http://ionicframework.com/docs/v2/theming/
// Ionic Shared Functions
// --------------------------------------------------
// Makes Ionic Sass functions available to your App
@import 'globals.core';
// App Shared Variables
// --------------------------------------------------
// To customize the look and feel of this app, you can override
// the Sass variables found in Ionic's source scss files. Setting
// variables before Ionic's Sass will use these variables rather than
// Ionic's default Sass variable values. App Shared Sass imports belong
// in the app.core.scss file and not this file. Sass variables specific
// to the mode belong in either the app.ios.scss or app.md.scss files.
// App Shared Color Variables
// --------------------------------------------------
// It's highly recommended to change the default colors
// to match your app's branding. Ionic uses a Sass map of
// colors so you can add, rename and remove colors as needed.
// The "primary" color is the only required color in the map.
// Both iOS and MD colors can be further customized if colors
// are different per mode.
$colors: (
primary: #387ef5,
secondary: #32db64,
danger: #f53d3d,
light: #f4f4f4,
dark: #222,
favorite: #69BB7B
);

31
app/theme/app.wp.scss Normal file
View File

@@ -0,0 +1,31 @@
// http://ionicframework.com/docs/v2/theming/
// App Shared Variables
// --------------------------------------------------
// Shared Sass variables go in the app.variables.scss file
@import 'app.variables';
// App Windows Variables
// --------------------------------------------------
// Windows only Sass variables can go here
// Ionic Windows Sass
// --------------------------------------------------
// Custom App variables must be declared before importing Ionic.
// Ionic will use its default values when a custom variable isn't provided.
@import "ionic.wp";
// App Shared Sass
// --------------------------------------------------
// All Sass files that make up this app goes into the app.core.scss file.
// For simpler CSS overrides, custom app CSS must come after Ionic's CSS.
@import 'app.core';
// App Windows Only Sass
// --------------------------------------------------
// CSS that should only apply to the Windows app