Supabase Notification System

Profile picture of ben

Draft

Dec 1, 2023

ยท

4 min read

ยท

823 Views


Hey ๐Ÿ‘‹ Ever wondered how those cool notifications magically appear on your screens? Well, today, we're pulling back the curtain to show you the ins and outs of our notification system. It's the secret sauce that keeps our community buzzing with activity! ๐ŸŽ‰

Understanding What We Needed:

1. Diverse Notification Channels ๐Ÿ“ฌ๐Ÿ””:

Our platform is like a notification buffet! We've got emails, push notifications, and in-app pings. Why? Because everyone's got their favorite flavor! ๐Ÿฆ

2. Provider Flexibility ๐Ÿคธโ€โ™‚๏ธ:

We didn't want to lock ourselves in. Our system is like LEGO blocks; we can snap in new notification services whenever we want. Who doesn't love a little flexibility? ๐Ÿงฉ

3. User Control ๐ŸŽฎ:

We get it โ€“ not everyone wants to be bombarded. So, we let you call the shots. Customize your notifications to suit your vibe. ๐Ÿ•น๏ธ

Choosing Our Tech Heroes:

First of all - we use an abstract class to provide a nice way to implement multiple different tools

abstract class NotificationProvider {
  abstract notify(options: any): void;
}

1. Mailgun for Email Magic ๐Ÿ’Œ:

Mailgun is like our postal service, but way cooler. Check out how we send those snazzy emails!

class MailgunProvider extends NotificationProvider {
  private readonly apiKey: string;
  private readonly domain: string;
  private mg;

  constructor(apiKey: string, domain: string) {
    super();
    this.apiKey = apiKey;
    this.domain = domain;

    const mailgun = new Mailgun(FormData);
    this.mg = mailgun.client({
      username: "api",
      key: this.apiKey,
    });
  }

  async notify(options: MailgunNotifyOptions): Promise<void> {
    try {
      // Send the email using Mailgun API
      await this.mg.messages.create(this.domain, {
        from: "DevsForDevs <[email protected]>",
        subject: options.subject,
        template: "default",
        to: options.recipientEmail,
        "h:X-Mailgun-Variables": JSON.stringify({
          // be sure to stringify your payload
          CTA_text: options.button.text,
          CTA_url: options.button.url,
          subject: options.subject,
          text: options.text,
        }),
      });

      console.log("Email sent successfully.");
    } catch (error) {
      console.error("Error sending email:", error);
      throw error;
    }
  }
}

2. OneSignal for Pushing It Real Good ๐Ÿ“ฒ:

OneSignal is our DJ for push notifications. It makes sure you don't miss the party! ๐ŸŽต

class OneSignalProvider extends NotificationProvider {
  private client;

  constructor(appId: string, apiKey: string) {
    super();
    this.client = new OneSignal.Client(appId, apiKey);
  }

  notify(options: OneSignalNotifyArgs): void {
    const notificationOptions: CreateNotificationBody = {
      contents: { en: options.text },
      include_external_user_ids: [options.userId],
    };
    if (options.url) notificationOptions.web_url = options.url;

    this.client.createNotification(notificationOptions);
  }
}

3. In-App Awesomeness with Supabase ๐Ÿš€:

For in-app vibes, we teamed up with Supabase. It's like our backstage manager for storing and fetching your in-app notifications.

class InAppProvider extends NotificationProvider {
  async notify(options: InAppNotifyArgs): Promise<void> {
    const supabase = serverSupabaseServiceRole<Database>(options.event);
    const { error } = await supabase.from("InAppNotification").insert({
      target: options.targetId,
      origin: options.originId,
      notification_type: options.notificationType,
      comment_id: options.commentId,
      blog_id: options.blogId,
    });
    if (error) console.error(error);

    const { error: badgeError } = await supabase.rpc("add_notification_count", {
      userid: options.targetId,
    });
    if (badgeError) console.error(badgeError);
  }
}

Making the Notifications Dance:

1. Notification Settings โš™๏ธ:

Before we send anything your way, we check your settings. We want to respect your choices!

if (
      (provider === "email" || provider === "push") &&
      setting &&
      !setting[`${provider}_enabled` as keyof typeof setting]
    ) {
      continue;
    }

This is done using a simple for loop, that continues if you don't want to receive either push or email notifications.

2. Sending the Good Vibes ๐ŸŒŸ:

Here's where the magic happens! Our sendNotification function orchestrates everything. It checks your settings and sends notifications just the way you like 'em

await providerClasses[provider]!.notify(providerOptions);

Wrapping It Up:

Creating our notification system was like crafting the perfect cup of coffee โ€“ a blend of art and science. As DevsForDevs grows, so will our notifications. We're committed to keeping you in the loop in the coolest way possible! ๐Ÿš€โœ‰๏ธ๐Ÿ’ฌ

Remember, at the heart of it all, communication is what keeps our community alive. Cheers to more notifications and epic moments on DevsForDevs! ๐ŸŽ‰


Profile picture of ben

Written By

Ben Herbst

No bio found