Supabase Notification System

Profile picture of ben

Draft

Dec 1, 2023

·

4 min read

·

879 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