-
Notifications
You must be signed in to change notification settings - Fork 2.2k
/
Copy pathupboats.component.ts
82 lines (72 loc) · 2.67 KB
/
upboats.component.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import { Component, OnInit, Optional } from '@angular/core';
import { Observable, of } from 'rxjs';
import { shareReplay } from 'rxjs/operators';
import { traceUntilFirst } from '@angular/fire/performance';
import { Auth, user, User } from '@angular/fire/auth';
import { addDoc, collection, collectionData, doc, Firestore, increment, orderBy, query, serverTimestamp, updateDoc } from '@angular/fire/firestore';
export type Animal = {
name: string,
upboats: number,
id: string,
hasPendingWrites: boolean,
};
@Component({
selector: 'app-upboats',
template: `
<ul>
<li *ngFor="let animal of animals | async">
<span>{{ animal.name }}</span>
<button (click)="upboat(animal.id)" [disabled]="(this.user | async) === null">👍</button>
<span>{{ animal.upboats }}</span>
<button (click)="downboat(animal.id)" [disabled]="(this.user | async) === null">👎</button>
<span *ngIf="animal.hasPendingWrites">🕒</span>
</li>
</ul>
<button (click)="newAnimal()" [disabled]="!this.user">New animal</button>
`,
styles: []
})
export class UpboatsComponent implements OnInit {
public readonly animals: Observable<Animal[]>;
public user: Observable<User|null>;
constructor(private readonly firestore: Firestore, @Optional() auth: Auth) {
// INVESTIGATE why do I need to share user to keep the zone stable?
// perhaps it related to why N+1 renders fail
this.user = auth ? user(auth).pipe(shareReplay({ bufferSize: 1, refCount: false })) : of(null);
const animalsCollection = collection(firestore, 'animals').withConverter<Animal>({
fromFirestore: snapshot => {
const { name, upboats } = snapshot.data();
const { id } = snapshot;
const { hasPendingWrites } = snapshot.metadata;
return { id, name, upboats, hasPendingWrites };
},
// TODO unused can we make implicit?
toFirestore: (it: any) => it,
});
const animalsQuery = query(animalsCollection, orderBy('upboats', 'desc'), orderBy('updatedAt', 'desc'));
this.animals = collectionData(animalsQuery).pipe(
traceUntilFirst('animals')
);
}
ngOnInit(): void {
}
async upboat(id: string) {
return await updateDoc(doc(this.firestore, `animals/${id}`), {
upboats: increment(1),
updatedAt: serverTimestamp(),
});
}
async downboat(id: string) {
return await updateDoc(doc(this.firestore, `animals/${id}`), {
upboats: increment(-1),
updatedAt: serverTimestamp(),
});
}
async newAnimal() {
return await addDoc(collection(this.firestore, 'animals'), {
name: prompt('Can haz name?'),
upboats: 1,
updatedAt: serverTimestamp(),
});
}
}