Skip to content
This repository was archived by the owner on Feb 6, 2024. It is now read-only.

Commit cdfe81d

Browse files
feat(#773): use stencil/store for api user
1 parent 92a584f commit cdfe81d

File tree

7 files changed

+75
-96
lines changed

7 files changed

+75
-96
lines changed

studio/src/app/components/core/app-user-info/app-user-info.tsx

Lines changed: 7 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,8 @@
1-
import {Component, Prop, State, h} from '@stencil/core';
2-
3-
import {Subscription} from 'rxjs';
1+
import {Component, Prop, h} from '@stencil/core';
42

53
import authStore from '../../../stores/auth.store';
64
import userStore from '../../../stores/user.store';
7-
8-
import {ApiUser} from '../../../models/api/api.user';
9-
10-
import {ApiUserService} from '../../../services/api/user/api.user.service';
11-
import {ApiUserFactoryService} from '../../../services/api/user/api.user.factory.service';
5+
import apiUserStore from '../../../stores/api.user.store';
126

137
@Component({
148
tag: 'app-user-info',
@@ -18,28 +12,6 @@ export class AppUserInfo {
1812
@Prop()
1913
avatarColSize: number = 4;
2014

21-
private apiUserService: ApiUserService;
22-
private apiUserSubscription: Subscription;
23-
24-
@State()
25-
private apiUser: ApiUser;
26-
27-
constructor() {
28-
this.apiUserService = ApiUserFactoryService.getInstance();
29-
}
30-
31-
componentWillLoad() {
32-
this.apiUserSubscription = this.apiUserService.watch().subscribe((user: ApiUser) => {
33-
this.apiUser = user;
34-
});
35-
}
36-
37-
componentDidUnload() {
38-
if (this.apiUserSubscription) {
39-
this.apiUserSubscription.unsubscribe();
40-
}
41-
}
42-
4315
render() {
4416
if (authStore.state.authUser) {
4517
return (
@@ -50,7 +22,11 @@ export class AppUserInfo {
5022
</ion-col>
5123
<ion-col size={'' + (12 - this.avatarColSize)} class="user-info">
5224
<ion-label>{userStore.state.name}</ion-label>
53-
<ion-label>{!authStore.state.authUser.anonymous && this.apiUser && this.apiUser.username ? '@' + this.apiUser.username : undefined}</ion-label>
25+
<ion-label>
26+
{!authStore.state.authUser.anonymous && apiUserStore.state.apiUser && apiUserStore.state.apiUser.username
27+
? '@' + apiUserStore.state.apiUser.username
28+
: undefined}
29+
</ion-label>
5430
</ion-col>
5531
</ion-row>
5632
</ion-grid>

studio/src/app/components/editor/publish/app-publish-edit/app-publish-edit.tsx

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,19 @@
11
import {Component, Event, EventEmitter, h, State} from '@stencil/core';
22

3-
import {filter, take} from 'rxjs/operators';
4-
53
import {debounce} from '@deckdeckgo/utils';
64

75
import deckStore from '../../../../stores/deck.store';
86
import errorStore from '../../../../stores/error.store';
97
import feedStore from '../../../../stores/feed.store';
108
import publishStore from '../../../../stores/publish.store';
9+
import apiUserStore from '../../../../stores/api.user.store';
1110

1211
import {Deck} from '../../../../models/data/deck';
1312

1413
import {Resources} from '../../../../utils/core/resources';
1514

1615
import {DeckService} from '../../../../services/data/deck/deck.service';
17-
import {ApiUser} from '../../../../models/api/api.user';
18-
import {ApiUserService} from '../../../../services/api/user/api.user.service';
1916
import {PublishService} from '../../../../services/editor/publish/publish.service';
20-
import {ApiUserFactoryService} from '../../../../services/api/user/api.user.factory.service';
2117

2218
interface CustomInputEvent extends KeyboardEvent {
2319
data: string | null;
@@ -55,16 +51,11 @@ export class AppPublishEdit {
5551

5652
@Event() private published: EventEmitter<string>;
5753

58-
private apiUser: ApiUser;
59-
private apiUserService: ApiUserService;
60-
6154
private publishService: PublishService;
6255

6356
constructor() {
6457
this.deckService = DeckService.getInstance();
6558

66-
this.apiUserService = ApiUserFactoryService.getInstance();
67-
6859
this.publishService = PublishService.getInstance();
6960

7061
this.debounceUpdateDeck = debounce(async () => {
@@ -74,16 +65,6 @@ export class AppPublishEdit {
7465

7566
async componentWillLoad() {
7667
await this.init();
77-
78-
this.apiUserService
79-
.watch()
80-
.pipe(
81-
filter((apiUser: ApiUser) => apiUser !== null && apiUser !== undefined && !apiUser.anonymous),
82-
take(1)
83-
)
84-
.subscribe(async (apiUser: ApiUser) => {
85-
this.apiUser = apiUser;
86-
});
8768
}
8869

8970
componentDidLoad() {
@@ -409,7 +390,7 @@ export class AppPublishEdit {
409390
private renderPublish() {
410391
if (!this.publishing) {
411392
return (
412-
<ion-button type="submit" disabled={!this.valid || this.disablePublish || !this.apiUser} color="tertiary" shape="round">
393+
<ion-button type="submit" disabled={!this.valid || this.disablePublish || !apiUserStore.state.apiUser} color="tertiary" shape="round">
413394
<ion-label>Publish now</ion-label>
414395
</ion-button>
415396
);

studio/src/app/pages/core/app-settings/app-settings.tsx

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import {Component, Listen, State, h, Element} from '@stencil/core';
22
import {loadingController, modalController, OverlayEventDetail} from '@ionic/core';
33

4-
import {filter, take} from 'rxjs/operators';
5-
64
import firebase from '@firebase/app';
75
import '@firebase/auth';
86

@@ -11,6 +9,7 @@ import errorStore from '../../../stores/error.store';
119
import navStore, {NavDirection} from '../../../stores/nav.store';
1210
import authStore from '../../../stores/auth.store';
1311
import userStore from '../../../stores/user.store';
12+
import apiUserStore from '../../../stores/api.user.store';
1413

1514
import {ApiUser} from '../../../models/api/api.user';
1615
import {User} from '../../../models/data/user';
@@ -79,7 +78,8 @@ export class AppHome {
7978
@State()
8079
private custom: string = undefined;
8180

82-
private destroyListener;
81+
private destroyUserListener;
82+
private destroyApiUserListener;
8383

8484
constructor() {
8585
this.apiUserService = ApiUserFactoryService.getInstance();
@@ -89,38 +89,53 @@ export class AppHome {
8989
this.themeService = ThemeService.getInstance();
9090
}
9191

92-
async componentWillLoad() {
93-
this.apiUserService
94-
.watch()
95-
.pipe(
96-
filter((apiUser: ApiUser) => apiUser !== null && apiUser !== undefined && !apiUser.anonymous),
97-
take(1)
98-
)
99-
.subscribe(async (apiUser: ApiUser) => {
100-
this.apiUser = apiUser;
101-
102-
this.apiUsername = this.apiUser.username;
103-
});
92+
async componentDidLoad() {
93+
const promises: Promise<void>[] = [this.initUser(), this.initApiUser()];
94+
await Promise.all(promises);
10495
}
10596

106-
async componentDidLoad() {
97+
private async initUser() {
10798
if (userStore.state.user) {
10899
await this.initSocial();
109100
} else {
110-
this.destroyListener = userStore.onChange('user', async () => {
101+
this.destroyUserListener = userStore.onChange('user', async () => {
111102
await this.initSocial();
112103
});
113104
}
114105
}
115106

107+
private async initApiUser() {
108+
if (apiUserStore.state.apiUser) {
109+
await this.initUsername();
110+
} else {
111+
this.destroyApiUserListener = apiUserStore.onChange('apiUser', async () => {
112+
await this.initUsername();
113+
});
114+
}
115+
}
116+
116117
componentDidUnload() {
117-
if (this.destroyListener) {
118-
this.destroyListener();
118+
if (this.destroyUserListener) {
119+
this.destroyUserListener();
120+
}
121+
122+
if (this.destroyApiUserListener) {
123+
this.destroyApiUserListener();
119124
}
120125
}
121126

127+
private initUsername() {
128+
if (!apiUserStore.state.apiUser || apiUserStore.state.apiUser === undefined || apiUserStore.state.apiUser.anonymous) {
129+
return;
130+
}
131+
132+
this.apiUser = apiUserStore.state.apiUser;
133+
134+
this.apiUsername = this.apiUser.username;
135+
}
136+
122137
private async initSocial() {
123-
if (!userStore.state.user || !userStore.state.user.data || userStore.state.user.data.anonymous) {
138+
if (!userStore.state.user || userStore.state.user === undefined || !userStore.state.user.data || userStore.state.user.data.anonymous) {
124139
return;
125140
}
126141

studio/src/app/services/api/user/api.user.mock.service.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import apiUserStore from '../../../stores/api.user.store';
2+
13
import {ApiUser, ApiUserInfo} from '../../../models/api/api.user';
24

35
import {ApiUserService} from './api.user.service';
@@ -12,7 +14,7 @@ export class ApiUserMockService extends ApiUserService {
1214
return new Promise<ApiUser>(async (resolve) => {
1315
const testUser: ApiUser = await this.createTestUserInfo(apiUserInfo);
1416

15-
this.apiUserSubject.next(testUser);
17+
apiUserStore.state.apiUser = {...testUser};
1618

1719
resolve(testUser);
1820
});
@@ -38,7 +40,7 @@ export class ApiUserMockService extends ApiUserService {
3840
id: apiUserInfo.firebase_uid,
3941
anonymous: false,
4042
firebase_uid: apiUserInfo.firebase_uid,
41-
username: 'Peter Parker'
43+
username: 'Peter Parker',
4244
};
4345

4446
resolve(testUser);

studio/src/app/services/api/user/api.user.prod.service.tsx

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import apiUserStore from '../../../stores/api.user.store';
2+
13
import {ApiUser, ApiUserInfo} from '../../../models/api/api.user';
24

35
import {EnvironmentConfigService} from '../../core/environment/environment-config.service';
@@ -17,9 +19,9 @@ export class ApiUserProdService extends ApiUserService {
1719
headers: {
1820
Accept: 'application/json',
1921
'Content-Type': 'application/json',
20-
Authorization: `Bearer ${token}`
22+
Authorization: `Bearer ${token}`,
2123
},
22-
body: JSON.stringify(apiUserInfo)
24+
body: JSON.stringify(apiUserInfo),
2325
});
2426

2527
if (!rawResponse || (!rawResponse.ok && rawResponse.status !== 409)) {
@@ -29,7 +31,7 @@ export class ApiUserProdService extends ApiUserService {
2931

3032
const persistedUser: ApiUser = await rawResponse.json();
3133

32-
this.apiUserSubject.next(persistedUser);
34+
apiUserStore.state.apiUser = {...persistedUser};
3335

3436
resolve(persistedUser);
3537
} catch (err) {
@@ -49,8 +51,8 @@ export class ApiUserProdService extends ApiUserService {
4951
headers: {
5052
Accept: 'application/json',
5153
'Content-Type': 'application/json',
52-
Authorization: `Bearer ${token}`
53-
}
54+
Authorization: `Bearer ${token}`,
55+
},
5456
});
5557

5658
if (!rawResponse || !rawResponse.ok) {
@@ -75,8 +77,8 @@ export class ApiUserProdService extends ApiUserService {
7577
method: 'GET',
7678
headers: {
7779
Accept: 'application/json',
78-
'Content-Type': 'application/json'
79-
}
80+
'Content-Type': 'application/json',
81+
},
8082
});
8183

8284
if (!rawResponse || !rawResponse.ok) {
@@ -87,7 +89,7 @@ export class ApiUserProdService extends ApiUserService {
8789

8890
const persistedUser: ApiUser = await rawResponse.json();
8991

90-
this.apiUserSubject.next(persistedUser);
92+
apiUserStore.state.apiUser = {...persistedUser};
9193

9294
resolve(persistedUser);
9395
} catch (err) {

studio/src/app/services/api/user/api.user.service.tsx

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
import {Observable, ReplaySubject} from 'rxjs';
1+
import apiUserStore from '../../../stores/api.user.store';
22

33
import {ApiUser, ApiUserInfo} from '../../../models/api/api.user';
44
import {AuthUser} from '../../../models/auth/auth.user';
55

66
export abstract class ApiUserService {
7-
protected apiUserSubject: ReplaySubject<ApiUser> = new ReplaySubject(1);
8-
97
abstract query(apiUserInfo: ApiUserInfo | ApiUser, token: string, context: string, method: string): Promise<ApiUser>;
108

119
abstract delete(userId: string, token: string): Promise<void>;
@@ -41,12 +39,8 @@ export abstract class ApiUserService {
4139
});
4240
}
4341

44-
signOut(): Promise<void> {
45-
return new Promise<void>(async (resolve) => {
46-
this.apiUserSubject.next(null);
47-
48-
resolve();
49-
});
42+
async signOut() {
43+
apiUserStore.reset();
5044
}
5145

5246
post(apiUser: ApiUserInfo, token: string): Promise<ApiUser> {
@@ -57,10 +51,6 @@ export abstract class ApiUserService {
5751
return this.query(apiUser, token, `/users/${userId}`, 'PUT');
5852
}
5953

60-
watch(): Observable<ApiUser> {
61-
return this.apiUserSubject.asObservable();
62-
}
63-
6454
private createUserInfo(authUser: AuthUser): Promise<ApiUserInfo> {
6555
return new Promise<ApiUserInfo>((resolve) => {
6656
if (!authUser) {
@@ -71,7 +61,7 @@ export abstract class ApiUserService {
7161
const apiUserInfo: ApiUserInfo = {
7262
anonymous: authUser.anonymous,
7363
firebase_uid: authUser.uid,
74-
email: authUser.anonymous ? null : authUser.email
64+
email: authUser.anonymous ? null : authUser.email,
7565
};
7666

7767
resolve(apiUserInfo);
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import {createStore} from '@stencil/store';
2+
3+
import {ApiUser} from '../models/api/api.user';
4+
5+
interface ApitUserStore {
6+
apiUser: ApiUser | undefined;
7+
}
8+
9+
const {state, onChange, reset} = createStore({
10+
apiUser: undefined,
11+
} as ApitUserStore);
12+
13+
export default {state, onChange, reset};

0 commit comments

Comments
 (0)