Skip to content

Commit d2401b1

Browse files
comments added to code, readme updated
1 parent f9680d7 commit d2401b1

File tree

3 files changed

+64
-67
lines changed

3 files changed

+64
-67
lines changed

README.md

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ Code taken from course.
2525

2626
## [RxJS operators](http://reactivex.io/documentation/observable.html)
2727

28+
**general** all operators return observables. You have to subscribe to observables.
29+
2830
**switchMap** for http requests that emit just one value and for long-lived streams for Firebase real-time database and authentication. They do not need to be unsubscribed as they complete after emission. **switch:** because the result observable has switched from emitting the values of the first inner observable, to emitting the values of the newly created inner (derived) observable. The previous inner observable is cancelled and the new observable is subscribed. **map:** because what is being mapped is the emitted source value, that is getting mapped to an observable using the mapping function passed to switchMap. (The alternative operator is mergeMap).
2931

3032
**of** used with a single value for an 'emit once and complete' stream.
@@ -33,11 +35,23 @@ Code taken from course.
3335

3436
**tap** used to perform side effects. Every data value is received from the source, an action is taken on a part of the data then the data passeed on unchanged.
3537

36-
**map** passes each source value through a transformation function then outputs the results, e.g map(x => 10*x)
38+
**map** transforms things. It passes each source value through a transformation function then outputs the results, e.g map(x => 10*x).
39+
40+
**pipe** composes operators. Creates a pipeline of small reusable operators like map and filter.
41+
42+
**from** converts a mix of other objects and data types into Observables
43+
44+
## Ionic Controllers Used
45+
46+
* [Alert Controller](https://ionicframework.com/docs/api/alert) alert appears on top of app contents.
47+
48+
* [Loading Controller](https://ionicframework.com/docs/api/loading) overlay used to display activity and block user input. Loading indicators can be created, including spinners.
3749

3850
## Observables
3951

40-
An [observable](https://rxjs-dev.firebaseapp.com/guide/observable) is created using 'new Observable'. It is subscribed to using an Observer and executed to deliver next / error / complete notices to the Observer, before the execution is disposed of. Sbscribers should be wrapped in try/catch blocks.
52+
An [observable](https://rxjs-dev.firebaseapp.com/guide/observable) is created using 'new Observable'. It is subscribed to using an Observer and executed to deliver next / error / complete notices to the Observer, before the execution is disposed of. Subscribers should be wrapped in try/catch blocks.
53+
54+
a [BehaviourSubject](http://reactivex.io/rxjs/manual/overview.html#behaviorsubject) is a subject that requires an initial value and emits its current value to subscribers.
4155

4256
## Array Operators
4357

@@ -58,6 +72,7 @@ An [observable](https://rxjs-dev.firebaseapp.com/guide/observable) is created us
5872
* [Google Firebase](https://firebase.google.com)
5973
* [Google Maps Javascript API](https://developers.google.com/maps/documentation/javascript/tutorial)
6074
* [Capacitor v1.1.1](https://capacitor.ionicframework.com/)
75+
* [Ionic PWA Elements](https://www.npmjs.com/package/@ionic/pwa-elements)
6176

6277
## Setup
6378

@@ -128,8 +143,7 @@ private getGoogleMaps(): Promise<any> {
128143
* [Google Maps Javascript API](https://developers.google.com/maps/documentation/javascript/tutorial) map-modal added to new-offer page. Clicking on 'SELECT LOCATION' will open Google Maps at a fixed location. Address of place extracted from Google Maps data and stored in Places database.
129144
* [Capacitor Geolocation API](https://capacitor.ionicframework.com/docs/apis/geolocation) used to provide current location.
130145
* [Capacitor Camera API](https://capacitor.ionicframework.com/docs/apis/camera) used to provide camera functionality.
131-
* [Firebase Auth API](https://firebase.google.com/docs/reference/rest/auth) used to control access to app.
132-
* [Cordova Local Storage](https://cordova.apache.org/docs/en/latest/cordova/storage/storage.html#localstorage) to save user user authentication token so a refresh etc. does not lose a user's settings.
146+
* [Fapacitor Local Storage](https://capacitor.ionicframework.com/docs/apis/storage/) API provides a key-value store for simple data. Used to save user authentication token so a refresh etc. does not lose a user's settings.
133147
* [Google Cloud Storage](https://www.npmjs.com/package/@google-cloud/storage) used for storage of image data.
134148
* Auth tokens on the backend.
135149

src/app/auth/auth.page.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { LoadingController, AlertController } from '@ionic/angular';
66

77
import { AuthService, AuthResponseData } from './auth.service';
88

9-
109
@Component({
1110
selector: 'app-auth',
1211
templateUrl: './auth.page.html',

src/app/auth/auth.service.ts

Lines changed: 46 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import { BehaviorSubject, from } from 'rxjs';
2-
import { Injectable, OnDestroy } from '@angular/core';
3-
import { HttpClient } from '@angular/common/http';
4-
import { Plugins } from '@capacitor/core';
5-
import { map, tap } from 'rxjs/operators';
1+
import {BehaviorSubject, from} from 'rxjs';
2+
import {Injectable, OnDestroy} from '@angular/core';
3+
import {HttpClient} from '@angular/common/http';
4+
import {Plugins} from '@capacitor/core';
5+
import {map, tap} from 'rxjs/operators';
66

7-
import { environment } from '../../environments/environment';
8-
import { User } from './user.model';
7+
import {environment} from '../../environments/environment';
8+
import {User} from './user.model';
99

1010
export interface AuthResponseData {
1111
kind: string;
@@ -21,10 +21,10 @@ export interface AuthResponseData {
2121
providedIn: 'root'
2222
})
2323
export class AuthService implements OnDestroy {
24-
2524
private _user = new BehaviorSubject<User>(null);
2625
private activeLogoutTimer: any;
2726

27+
// method to return true if user has auth token, false if not
2828
get userIsAuthenticated() {
2929
return this._user.asObservable().pipe(
3030
map(user => {
@@ -37,7 +37,7 @@ export class AuthService implements OnDestroy {
3737
);
3838
}
3939

40-
// function to return a userid observable
40+
// function to return userid as an observable
4141
get userId() {
4242
return this._user.asObservable().pipe(
4343
map(user => {
@@ -62,74 +62,74 @@ export class AuthService implements OnDestroy {
6262
);
6363
}
6464

65-
constructor(private http: HttpClient) { }
65+
constructor(private http: HttpClient) {}
6666

67+
// method to get data stored by Capacitor plugin then convert it back to a js object
6768
autoLogin() {
68-
return from(Plugins.Storage.get({ key: 'authData'})).pipe(
69+
return from(Plugins.Storage.get({key: 'authData'})).pipe(
6970
map(storedData => {
7071
if (!storedData || !storedData.value) {
7172
return null;
7273
}
7374
// create a constant that is a javascript object
7475
const parsedData = JSON.parse(storedData.value) as {
75-
token: string;
76-
tokenExpirationDate: string;
77-
userId: string;
78-
email: string;
76+
token: string
77+
tokenExpirationDate: string
78+
userId: string
79+
email: string
7980
};
80-
// create expiry time as a string in ISO format that can be used by the data constructor
81+
// recreate expiry time as a string in ISO format that can be used by the data constructor
8182
const expirationTime = new Date(parsedData.tokenExpirationDate);
8283
if (expirationTime <= new Date()) {
8384
return null;
8485
}
85-
const user = new User(
86-
parsedData.userId,
87-
parsedData.email,
88-
parsedData.token,
89-
expirationTime
90-
);
86+
const user = new User(parsedData.userId, parsedData.email, parsedData.token, expirationTime);
9187
return user;
92-
}),
93-
tap(user => {
94-
if (user) {
95-
this._user.next(user);
96-
this.autoLogout(user.tokenDuration);
97-
}
98-
}),
99-
map(user => {
100-
return !!user; // returns a boolean (true if there is a user, otherwise false)
101-
})
88+
}),
89+
tap(user => {
90+
if (user) {
91+
this._user.next(user);
92+
this.autoLogout(user.tokenDuration);
93+
}
94+
}),
95+
map(user => {
96+
return !!user; // returns a boolean (true if there is a user, otherwise false)
97+
})
10298
);
10399
}
104100

101+
// signup POST request method with a js object with user login info to a firebase backend http endpoint with an API key.
102+
// This will return js object AuthResponseData (kind, idToken, email, refreshToken, localId, expiresIn).
103+
// return observable to auth page. Bind the data returned from firebase to setUserData.
105104
signup(email: string, password: string) {
106105
return this.http
107106
.post<AuthResponseData>(
108107
`https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=${
109-
environment.firebaseAPIKey
108+
environment.firebaseAPIKey
110109
}`,
111-
{ email, password, returnSecureToken: true }
112-
)
110+
{email, password, returnSecureToken: true})
113111
.pipe(tap(this.setUserData.bind(this)));
114112
}
115113

114+
// will return AuthResponseData (kind, idToken, email, refreshToken, localId, expiresIn, registered boolean)
115+
// return observable to auth page. Bind the data returned from firebase to setUserData.
116116
login(email: string, password: string) {
117117
return this.http
118118
.post<AuthResponseData>(
119119
`https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=${
120-
environment.firebaseAPIKey
120+
environment.firebaseAPIKey
121121
}`,
122-
{ email, password, returnSecureToken: true }
123-
)
122+
{email, password, returnSecureToken: true})
124123
.pipe(tap(this.setUserData.bind(this)));
125124
}
126125

126+
// method to logout user by clearing timer, passing null to the _user behavioursubject and clearing the native storage.
127127
logout() {
128128
if (this.activeLogoutTimer) {
129129
clearTimeout(this.activeLogoutTimer);
130130
}
131131
this._user.next(null);
132-
Plugins.Storage.remove({ key: 'authData' });
132+
Plugins.Storage.remove({key: 'authData'});
133133
}
134134

135135
ngOnDestroy() {
@@ -148,39 +148,23 @@ export class AuthService implements OnDestroy {
148148
}
149149

150150
private setUserData(userData: AuthResponseData) {
151-
152151
// create const for time to expire in milliseconds
153-
const expirationTime = new Date(
154-
new Date().getTime() + +userData.expiresIn * 1000
155-
);
156-
const user = new User(
157-
userData.localId,
158-
userData.email,
159-
userData.idToken,
160-
expirationTime
161-
);
152+
const expirationTime = new Date(new Date().getTime() + +userData.expiresIn * 1000);
153+
const user = new User(userData.localId, userData.email, userData.idToken, expirationTime);
162154
this._user.next(user);
163155
this.autoLogout(user.tokenDuration);
164-
this.storeAuthData(
165-
userData.localId,
166-
userData.idToken,
167-
expirationTime.toISOString(),
168-
userData.email
169-
);
156+
this.storeAuthData(userData.localId, userData.idToken, expirationTime.toISOString(), userData.email);
170157
}
171158

172-
private storeAuthData(
173-
userId: string,
174-
token: string,
175-
tokenExpirationDate: string,
176-
email: string
177-
) {
159+
// method to store auth data using Capacitor storage plugin
160+
// convert to string using stringify as we cannot store a js object
161+
private storeAuthData(userId: string, token: string, tokenExpirationDate: string, email: string) {
178162
const data = JSON.stringify({
179163
userId,
180164
token,
181165
tokenExpirationDate,
182166
email
183167
});
184-
Plugins.Storage.set({ key: 'authData', value: data });
168+
Plugins.Storage.set({key: 'authData', value: data});
185169
}
186170
}

0 commit comments

Comments
 (0)