-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Implement receiving notifications * Add sending notifications * Change notification description and icon
- Loading branch information
Showing
8 changed files
with
154 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,41 @@ | ||
import * as functions from "firebase-functions"; | ||
|
||
// // Start writing Firebase Functions | ||
// // https://firebase.google.com/docs/functions/typescript | ||
// | ||
export const helloWorld = functions.https.onRequest((request, response) => { | ||
functions.logger.info("Hello logs!", {structuredData: true}); | ||
response.send("Hello from Firebase!"); | ||
import {pubsub} from "firebase-functions"; | ||
import * as admin from "firebase-admin"; | ||
import {MessagingPayload} from "firebase-admin/lib/messaging/messaging-api"; | ||
|
||
const app = admin.initializeApp(); | ||
const firestore = app.firestore(); | ||
const messaging = app.messaging(); | ||
|
||
export const sendPush = pubsub.schedule("every 1 minutes").onRun(async () => { | ||
const users = await firestore.collection("users").listDocuments(); | ||
users.forEach(async (user) => { | ||
const plants = await user.collection("plants").get(); | ||
plants.forEach(async (plant) => { | ||
const plantData = plant.data(); | ||
|
||
const timeFormatOptions: Intl.DateTimeFormatOptions = { | ||
timeZone: plantData.timezone, | ||
timeStyle: "short", | ||
}; | ||
// eslint-disable-next-line | ||
const timeInPlantTimezone = new Intl.DateTimeFormat("PL", timeFormatOptions).format(); | ||
|
||
if (timeInPlantTimezone === plantData.waterTime) { | ||
const payload: MessagingPayload = { | ||
notification: { | ||
title: `It's time to water ${plantData.name}`, | ||
body: plantData.description, | ||
image: plantData.imageUrl ? plantData.imageUrl : "https://watering-reminder.web.app/assets/images/default_plant_image.png", | ||
icon: "https://watering-reminder.web.app/assets/icons/icon-144x144.png", | ||
}, | ||
}; | ||
|
||
const fcmTokens = await user.collection("fcmTokens").get(); | ||
fcmTokens.forEach(async (token) => { | ||
const tokenData = token.data() as { fcmToken: string }; | ||
await messaging.sendToDevice(tokenData.fcmToken, payload); | ||
}); | ||
} | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,31 @@ | ||
<p>dashboard works!</p> | ||
<button (click)="logout()">Logout</button> | ||
<div *ngIf="notificationsService.areNotificationsAllowed; then notificationsAllowedBlock else notificationsNotAllowedBlock"></div> | ||
|
||
<div *ngIf="isLoading; then loadingBlock else loadedBlock"></div> | ||
|
||
<ng-template #loadingBlock> | ||
<p>Loading</p> | ||
<ng-template #notificationsNotAllowedBlock> | ||
<p>You have to allow push notifications to use this app.</p> | ||
</ng-template> | ||
|
||
<ng-template #loadedBlock> | ||
<div *ngIf="plantsService.plantsAreEmpty$ | async; then plantsEmptyBlock else plantsNotEmptyBlock"></div> | ||
<ng-template #notificationsAllowedBlock> | ||
<p>dashboard works!</p> | ||
<button (click)="logout()">Logout</button><br> | ||
|
||
<div *ngIf="isLoading; then loadingBlock else loadedBlock"></div> | ||
|
||
<ng-template #plantsEmptyBlock> | ||
<p>You have no plants.</p> | ||
<button routerLink="/add-plant">Add your first plant</button> | ||
<ng-template #loadingBlock> | ||
<p>Loading</p> | ||
</ng-template> | ||
|
||
<ng-template #plantsNotEmptyBlock> | ||
<button routerLink="/add-plant">Add a plant</button> | ||
<app-plants-list-element *ngFor="let plant of plantsService.plants$ | async" [plant]="plant"> | ||
</app-plants-list-element> | ||
<ng-template #loadedBlock> | ||
<div *ngIf="plantsService.plantsAreEmpty$ | async; then plantsEmptyBlock else plantsNotEmptyBlock"></div> | ||
|
||
<ng-template #plantsEmptyBlock> | ||
<p>You have no plants.</p> | ||
<button routerLink="/add-plant">Add your first plant</button> | ||
</ng-template> | ||
|
||
<ng-template #plantsNotEmptyBlock> | ||
<button routerLink="/add-plant">Add a plant</button> | ||
<app-plants-list-element *ngFor="let plant of plantsService.plants$ | async" [plant]="plant"> | ||
</app-plants-list-element> | ||
</ng-template> | ||
</ng-template> | ||
</ng-template> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
16 changes: 16 additions & 0 deletions
16
src/app/services/notifiications/notifications.service.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { TestBed } from '@angular/core/testing'; | ||
|
||
import { NotificationsService } from './notifications.service'; | ||
|
||
describe('NotificationsService', () => { | ||
let service: NotificationsService; | ||
|
||
beforeEach(() => { | ||
TestBed.configureTestingModule({}); | ||
service = TestBed.inject(NotificationsService); | ||
}); | ||
|
||
it('should be created', () => { | ||
expect(service).toBeTruthy(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { Injectable } from '@angular/core'; | ||
import { addDoc, collection, deleteDoc, doc, Firestore, setDoc } from '@angular/fire/firestore' | ||
import { Messaging } from '@angular/fire/messaging' | ||
import { getToken } from '@firebase/messaging' | ||
import { lastValueFrom, take } from 'rxjs' | ||
import { AuthService } from '../auth/auth.service' | ||
|
||
@Injectable({ | ||
providedIn: 'root' | ||
}) | ||
export class NotificationsService { | ||
areNotificationsAllowed = Notification.permission === 'granted' | ||
|
||
constructor(private messaging: Messaging, private auth: AuthService, private firestore: Firestore) { } | ||
|
||
async registerToken() { | ||
const user = await lastValueFrom(this.auth.user$.pipe(take(1))) | ||
|
||
if (!user) { | ||
throw new Error("User is not logged in") | ||
} | ||
|
||
const fcmToken = await getToken(this.messaging) | ||
const d = doc(this.firestore, "users", user.uid, "fcmTokens", fcmToken) | ||
await setDoc(d, { fcmToken }) | ||
this.areNotificationsAllowed = true | ||
} | ||
|
||
async unregisterToken() { | ||
const user = await lastValueFrom(this.auth.user$.pipe(take(1))) | ||
|
||
if (!user) { | ||
throw new Error("User is not logged in") | ||
} | ||
|
||
const fcmToken = await getToken(this.messaging) | ||
const d = doc(this.firestore, "users", user.uid, "fcmTokens", fcmToken) | ||
await deleteDoc(d) | ||
this.areNotificationsAllowed = false | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
importScripts('https://www.gstatic.com/firebasejs/8.10.0/firebase-app.js'); | ||
importScripts('https://www.gstatic.com/firebasejs/8.10.0/firebase-messaging.js'); | ||
|
||
// Initialize the Firebase app in the service worker by passing in | ||
// your app's Firebase config object. | ||
// https://firebase.google.com/docs/web/setup#config-object | ||
firebase.initializeApp({ | ||
apiKey: 'api-key', | ||
authDomain: 'project-id.firebaseapp.com', | ||
databaseURL: 'https://project-id.firebaseio.com', | ||
projectId: 'project-id', | ||
storageBucket: 'project-id.appspot.com', | ||
messagingSenderId: 'sender-id', | ||
appId: 'app-id', | ||
measurementId: 'G-measurement-id', | ||
}); | ||
|
||
// Retrieve an instance of Firebase Messaging so that it can handle background | ||
// messages. | ||
const messaging = firebase.messaging(); |