Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add realtime notification feature #431

Merged
merged 5 commits into from
Mar 4, 2024

Conversation

xingsy97
Copy link
Contributor

@xingsy97 xingsy97 commented Feb 2, 2024

Summary

add realtime notification feature for portal powered by Azure Web PubSub For Socket.IO

This draft PR doesn't contain azure deployment code. So user have to use a pre-created Web PubSub resource, manually replace endpoint in packages/portal and add connection string in packages/realtime

How to use

  1. Create a Web PubSub For Socket.IO resource.
  2. Click key tab in resource portal, copy connection string.
  3. Rename .env.example under packages/realtime/ to .env. Then fill in copied connection string to variable WebPubSubConnectionString
  4. Copy the endpoint part in connection string (e.g. https://<resource-name>.webpubsub.azure.com). And use it replace the default endpoint in packages/portal/src/app/shared/realtime.service.ts:L14
  5. Follow original README to go on.

Feature specification

The realtime notification has four scenarios as cited below. See complete specification in the internal doc.

Use-case 1 – Anonymous user favorites a listing

Given an anonymous user is browsing the application. When an authenticated user clicks on the "Favorite" button for a listing named [listing-name]. Then a real-time notification is sent via Azure Web PubSub and Socket.io. And the notification message displayed is: "A user has favorited the listing [listing-name]."

Use-case 2 – Authenticated user favorites a listing

Given an authenticated user is logged into the application. When the user clicks on the "Favorite" button for a listing named [listing-name]. Then a real-time notification is sent via Azure Web PubSub and Socket.io. And the notification message displayed is: "Hurry up! Another user has favorited the listing [listing-name]."

Use-case 3 – Authenticated user has started a booking process but didn’t complete a payment

Given an authenticated user is logged into the application. When the user attempts to book a listing named [listing-name] but doesn't complete the payment process. Then a real-time notification is sent via Azure Web PubSub and Socket.io. And the notification message displayed is: "Hurry up! Another user has booked the listing [listing-name] but didn't complete the payment."

Use-case 4 – Authenticated user receives a notification about unavailable listing

Given an authenticated user is logged into the application. And the user has favorited a listing named [listing-name]. When the listing [listing-name] is booked by another user and becomes unavailable between the dates [dates]. Then a real-time notification is sent via Azure Web PubSub and Socket.io. And the notification message displayed is: "[Listing-name] in your favorites has been booked and it's no longer available between the dates [dates]."

Other reference

https://learn.microsoft.com/en-us/azure/azure-web-pubsub/socketio-migrate-from-self-hosted

@xingsy97 xingsy97 changed the title [feat] add realtime notification feature feat: add realtime notification feature Feb 2, 2024
@manekinekko manekinekko marked this pull request as ready for review February 2, 2024 15:50
@manekinekko manekinekko self-assigned this Feb 2, 2024
@@ -8,6 +8,7 @@
"start:services": "docker compose up",
"start:api": "npm run start --workspace=api",
"start:website": "npm run start:swa --workspace=portal",
"start:realtime": "npm run start --workspace=realtime",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe start:notifications is more idomatic?

import { environment } from "../../environments/environment";
import { CardListComponent } from "../shared/card-list/card-list.component";
import { FavoriteService } from "../shared/favorite.service";
import { InfiniteScrollingDirective } from "../shared/infinite-scrolling.directive";
import { ListingService } from "../shared/listing.service";
import { UserService } from "../shared/user/user.service";
import { RealtimeService } from "../shared/realtime.service";

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe NotificationService, to consolidate?


// Get notification when someone favourtied a listing
this.realtimeService.getNotifiedForFavourite((listingTitle) => {
const notifyMessage = this.user?.name?.length > 0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably need to move all those strings to global or component configs.

const favourites: Array<Listing> = await this.favoriteService.getFavoritesByUser(this.user) ?? [];

for (const favour of favourites) {
if (favour.id === listing.id) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is just a styling suggestion but I feel the name is more representatitve. 'for (const fave of favorites) '

@@ -13,7 +16,7 @@ export class FavoriteService {
user,
}),
});

this.realtimeService.broadcastFavouriteNotification(listing);
return resource.status === 200;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For extensibility purposes... can that broadcast method be passed items that could be of different types? The we can just call it broadcast

@@ -80,6 +83,13 @@ export class ListingService {
if (resource.status !== 200) {
throw new Error(checkoutSession.error);
}
const listing = await this.getListingById(reservationDetails.listingId ?? "");
if (listing) {
this.realtimeService.broadcastCheckoutNotification(listing, reservationDetails.from, reservationDetails.to);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't gotten yet to the implementation of this broadcast. Maybe we can consolidate to one?


if (!environment.notificationUrl || !environment.notificationPath) {
// TODO: disable this feature at the injector level if the URL or Path is not set.
alert("RealtimeService: Notification URL or Path is not set. Please check environment.ts file.");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove alerts, we may want to only let deverlopers know on dev env?

broadcastCheckoutNotification(listing: Listing, from: string, to: string) {
this.client.emit("sendCheckout", listing, from, to);
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As suggested, maybe we make broadcast a single method that takes a type of { item, from?, to?) to consolidate maintenance and admit extensibility? This is not a blocker to merge at all. Just an optimization suggestion.

this.client.emit("sendCheckout", listing, from, to);
}

getNotifiedForFavourite(notifyAction: (listingTitle: string) => void | Promise<void>) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This two notifications could also be consolidated in the same fashion. on('event', message) {... }


body {
.mdc-snackbar .mdc-snackbar__surface
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

formatting -please move opening curly bracket to first line.

@anfibiacreativa
Copy link
Member

@manekinekko what's the current status? Can we proceed to merge without refactoring changes?

@manekinekko
Copy link
Collaborator

I was working on adding bicep/azd iac part of this PR, but I am hitting a blocking issue. I am going to merge this PR as-is and will add bicep/azd deployment in a different PR. Will also refactor code in a separate PR.

@anfibiacreativa
Copy link
Member

I was working on adding bicep/azd iac part of this PR, but I am hitting a blocking issue. I am going to merge this PR as-is and will add bicep/azd deployment in a different PR. Will also refactor code in a separate PR.

Agreed. Can we merge before the event coming up?

* chore: minor changes

* chore: add azd support (wip)
@manekinekko manekinekko merged commit beb7633 into Azure-Samples:develop Mar 4, 2024
devin-ai-integration bot pushed a commit to altsang/contoso-real-estate that referenced this pull request May 14, 2024
* feat: add realtime feature
* fix(realtime): update RealtimeService
* chore: minor changes (Azure-Samples#2)
* chore: add azd support (wip)

---------

Co-authored-by: Wassim Chegham <github@wassim.dev>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants