Skip to content

Commit 59b6656

Browse files
committed
15.9 User Observable, userId, token storage
1 parent e15f0ae commit 59b6656

File tree

7 files changed

+166
-101
lines changed

7 files changed

+166
-101
lines changed

src/app/auth/auth.page.ts

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { Component, OnInit } from '@angular/core';
2-
import { AuthService } from './auth.service';
2+
import { AuthResponseData, AuthService } from './auth.service';
33
import { Router } from '@angular/router';
44
import { AlertController, LoadingController } from '@ionic/angular';
55
import { NgForm } from '@angular/forms';
6+
import { Observable } from 'rxjs';
67

78
@Component({
89
selector: 'app-auth',
@@ -24,22 +25,30 @@ export class AuthPage implements OnInit {
2425

2526
authenticate(email: string, password: string) {
2627
this.isLoading = true;
27-
this.authService.login();
2828
this.loadingCtrl
2929
.create({
3030
keyboardClose: true,
3131
message: 'Logging in...',
3232
})
3333
.then((loadingEl) => {
3434
loadingEl.present();
35-
this.authService.signup(email, password).subscribe((resData) => {
36-
this.isLoading = false;
37-
loadingEl.dismiss();
38-
this.router.navigateByUrl('/places/tabs/discover');
39-
}, errRes => {
40-
loadingEl.dismiss();
41-
this.showAlert(errRes.error.error.message);
42-
});
35+
let authObs: Observable<AuthResponseData>;
36+
if (this.isLogin) {
37+
authObs = this.authService.login(email, password);
38+
} else {
39+
authObs = this.authService.signup(email, password);
40+
}
41+
authObs.subscribe(
42+
(resData) => {
43+
this.isLoading = false;
44+
loadingEl.dismiss();
45+
this.router.navigateByUrl('/places/tabs/discover');
46+
},
47+
(errRes) => {
48+
loadingEl.dismiss();
49+
this.showAlert(errRes.error.error.message);
50+
}
51+
);
4352
});
4453
}
4554

src/app/auth/auth.service.ts

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { HttpClient } from '@angular/common/http';
22
import { Injectable } from '@angular/core';
33
import { environment } from '../../environments/environment';
4+
import { BehaviorSubject, map, tap } from 'rxjs';
5+
import { User } from './user.model';
46

5-
interface AuthResponseData {
7+
export interface AuthResponseData {
68
kind: string;
79
idToken: string;
810
email: string;
@@ -16,28 +18,61 @@ interface AuthResponseData {
1618
providedIn: 'root',
1719
})
1820
export class AuthService {
19-
private _userIsAuthenticated = false;
20-
private _userId = null;
21+
private _user = new BehaviorSubject<User>(null);
2122

2223
get userIsAuthenticated() {
23-
return this._userIsAuthenticated;
24+
return this._user.asObservable().pipe(
25+
map((user) => {
26+
if (user) {
27+
return !!user;
28+
} else {
29+
return false;
30+
}
31+
})
32+
);
2433
}
2534
get userId() {
26-
return this._userId;
35+
return this._user.asObservable().pipe(
36+
map((user) => {
37+
if (user) {
38+
return user.id;
39+
} else {
40+
return null;
41+
}
42+
})
43+
);
2744
}
2845
constructor(private http: HttpClient) {}
2946

3047
signup(email: string, password: string) {
48+
return this.http
49+
.post<AuthResponseData>(
50+
`https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=${environment.firebaseAPIKey}`,
51+
{ email: email, password: password, returnSecureToken: true }
52+
)
53+
.pipe(tap(this.setUserData.bind(this)));
54+
}
55+
56+
login(email: string, password: string) {
3157
return this.http.post<AuthResponseData>(
32-
`https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=${environment.firebaseAPIKey}`,
58+
`https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=${environment.firebaseAPIKey}`,
3359
{ email: email, password: password, returnSecureToken: true }
34-
);
60+
).pipe(tap(this.setUserData.bind(this)));
3561
}
3662

37-
login() {
38-
this._userIsAuthenticated = true;
39-
}
4063
logout() {
41-
this._userIsAuthenticated = false;
64+
this._user.next(null);
65+
}
66+
67+
private setUserData(userData: AuthResponseData) {
68+
const expTime = new Date().getTime() + +userData.expiresIn * 1000;
69+
this._user.next(
70+
new User(
71+
userData.localId,
72+
userData.email,
73+
userData.idToken,
74+
new Date(expTime)
75+
)
76+
);
4277
}
4378
}

src/app/auth/user.model.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
export class User {
2+
constructor(
3+
public id: string,
4+
public email: string,
5+
private _token: string,
6+
private tokenExpirationDate: Date
7+
) {}
8+
get token() {
9+
if(!this.tokenExpirationDate || this.tokenExpirationDate <= new Date()) {
10+
return null;
11+
}
12+
return this._token;
13+
}
14+
}

src/app/bookings/booking.service.ts

Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -40,34 +40,40 @@ export class BookingService {
4040
dateTo: Date
4141
) {
4242
let generatedId: string;
43-
const newBooking = new Booking(
44-
Math.random().toString(),
45-
placeId,
46-
this.auth.userId,
47-
placeTitle,
48-
placeImage,
49-
firstName,
50-
lastName,
51-
guestNumber,
52-
dateFrom,
53-
dateTo
43+
let newBooking;
44+
return this.auth.userId.pipe(
45+
take(1),
46+
switchMap((userId) => {
47+
if (!userId) {
48+
throw new Error('No user Id found!');
49+
}
50+
newBooking = new Booking(
51+
Math.random().toString(),
52+
placeId,
53+
userId,
54+
placeTitle,
55+
placeImage,
56+
firstName,
57+
lastName,
58+
guestNumber,
59+
dateFrom,
60+
dateTo
61+
);
62+
return this.http.post<{ name: string }>(
63+
'https://ionic-angular-backend-66c35-default-rtdb.asia-southeast1.firebasedatabase.app/bookings.json',
64+
{ ...newBooking, id: null }
65+
);
66+
}),
67+
switchMap((resData) => {
68+
generatedId = resData.name;
69+
return this.bookings;
70+
}),
71+
take(1),
72+
tap((bookings) => {
73+
newBooking.id = generatedId;
74+
this._bookings.next(bookings.concat(newBooking));
75+
})
5476
);
55-
return this.http
56-
.post<{ name: string }>(
57-
'https://ionic-angular-backend-66c35-default-rtdb.asia-southeast1.firebasedatabase.app/bookings.json',
58-
{ ...newBooking, id: null }
59-
)
60-
.pipe(
61-
switchMap((resData) => {
62-
generatedId = resData.name;
63-
return this.bookings;
64-
}),
65-
take(1),
66-
tap((bookings) => {
67-
newBooking.id = generatedId;
68-
this._bookings.next(bookings.concat(newBooking));
69-
})
70-
);
7177
}
7278

7379
cancelBooking(bookingId: string) {

src/app/places/discover/discover.page.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Component, OnDestroy, OnInit } from '@angular/core';
22
import { PlacesService } from '../places.service';
33
import { Place } from '../place.model';
44
import { InfiniteScrollCustomEvent, SegmentChangeEventDetail } from '@ionic/angular';
5-
import { Subscription } from 'rxjs';
5+
import { Subscription, take } from 'rxjs';
66
import { AuthService } from '../../auth/auth.service';
77

88
@Component({
@@ -39,7 +39,7 @@ export class DiscoverPage implements OnInit, OnDestroy {
3939
this.isLoading = true;
4040
this.placeService.fetchPlaces().subscribe(() => {
4141
this.isLoading = false;
42-
})
42+
});
4343
}
4444

4545
onIonInfinite(ev) {
@@ -66,14 +66,14 @@ export class DiscoverPage implements OnInit, OnDestroy {
6666
}
6767

6868
onFilterUpdate(event: any) {
69-
console.log(event.detail);
70-
if (event.detail.value === 'all') {
71-
this.relevantPlaces = this.loadedPlaces;
72-
} else {
73-
this.relevantPlaces = this.loadedPlaces.filter(
74-
(place) => place.userId !== this.authService.userId
75-
);
76-
console.log(this.relevantPlaces);
77-
}
69+
this.authService.userId.pipe(take(1)).subscribe((userId) => {
70+
if (event.detail.value === 'all') {
71+
this.relevantPlaces = this.loadedPlaces;
72+
} else {
73+
this.relevantPlaces = this.loadedPlaces.filter(
74+
(place) => place.userId !== userId
75+
);
76+
}
77+
});
7878
}
7979
}

src/app/places/discover/place-detail/place-detail.page.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { ActionSheetController, AlertController, LoadingController, ModalControl
44
import { CreateBookingComponent } from '../../../bookings/create-booking/create-booking.component';
55
import { Place } from '../../place.model';
66
import { PlacesService } from '../../places.service';
7-
import { Subscription } from 'rxjs';
7+
import { Subscription, switchMap } from 'rxjs';
88
import { BookingService } from '../../../bookings/booking.service';
99
import { AuthService } from '../../../auth/auth.service';
1010

@@ -38,10 +38,17 @@ export class PlaceDetailPage implements OnInit, OnDestroy {
3838
this.navctrl.navigateBack('/places/tabs/offers');
3939
return;
4040
}
41-
this.placeSub = this.placesService.getplace(paramMap.get('placeId')).subscribe(place => {
41+
let fetchedUserId: string;
42+
this.auth.userId.pipe(switchMap(userId => {
43+
if(!userId) {
44+
throw new Error('Found no user!');
45+
}
46+
fetchedUserId = userId;
47+
return this.placesService.getplace(paramMap.get('placeId'))
48+
})).subscribe(place => {
4249
this.isLoading = false;
4350
this.place = place;
44-
this.isBookable = place.userId !== this.auth.userId;
51+
this.isBookable = place.userId !== fetchedUserId;
4552
},
4653
(error) => {
4754
this.alert.create({

src/app/places/places.service.ts

Lines changed: 33 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,6 @@ export class PlacesService {
8787
{ image },
8888
{ responseType: 'text' }
8989
)
90-
.pipe(
91-
map((url) => {
92-
return url;
93-
})
94-
);
9590
}
9691

9792
addplaces(
@@ -103,53 +98,52 @@ export class PlacesService {
10398
imageUrl: string
10499
) {
105100
let generatedId: string;
106-
const newPlace = new Place(
107-
Math.random().toString(),
108-
title,
109-
description,
110-
imageUrl,
111-
price,
112-
dateFrom,
113-
dateTo,
114-
this.authService.userId
101+
let newPlace: Place;
102+
return this.authService.userId.pipe(
103+
take(1),
104+
switchMap((userId) => {
105+
if (!userId) {
106+
throw new Error('No User found');
107+
}
108+
newPlace = new Place(
109+
Math.random().toString(),
110+
title,
111+
description,
112+
imageUrl,
113+
price,
114+
dateFrom,
115+
dateTo,
116+
userId
117+
);
118+
return this.http.post<{ name: string }>(
119+
'https://ionic-angular-backend-66c35-default-rtdb.asia-southeast1.firebasedatabase.app/offered-places.json',
120+
{ ...newPlace, id: null }
121+
);
122+
}),
123+
switchMap((resData) => {
124+
generatedId = resData.name;
125+
return this.places;
126+
}),
127+
take(1),
128+
tap((places) => {
129+
newPlace.id = generatedId;
130+
this._places.next(places.concat(newPlace));
131+
})
115132
);
116-
return this.http
117-
.post<{ name: string }>(
118-
'https://ionic-angular-backend-66c35-default-rtdb.asia-southeast1.firebasedatabase.app/offered-places.json',
119-
{ ...newPlace, id: null }
120-
)
121-
.pipe(
122-
switchMap((resData) => {
123-
generatedId = resData.name;
124-
return this.places;
125-
}),
126-
take(1),
127-
tap((places) => {
128-
newPlace.id = generatedId;
129-
this._places.next(places.concat(newPlace));
130-
})
131-
);
132-
// return this._places.pipe(
133-
// take(1),
134-
// delay(1000),
135-
// tap((places) => {
136-
// this._places.next(places.concat(newPlace));
137-
// })
138-
// );
139133
}
140134

141135
updatePlace(placeId: string, title: string, description: string) {
142136
let updatedPlaces: Place[];
143137
return this.places.pipe(
144138
take(1),
145139
switchMap((places) => {
146-
if(!places || places.length <=0 ){
140+
if (!places || places.length <= 0) {
147141
return this.fetchPlaces();
148142
} else {
149143
return of(places);
150144
}
151145
}),
152-
switchMap(places => {
146+
switchMap((places) => {
153147
const updatedPlaceIndex = places.findIndex((pl) => pl.id === placeId);
154148
updatedPlaces = [...places];
155149
const oldPlace = updatedPlaces[updatedPlaceIndex];

0 commit comments

Comments
 (0)