npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@bigbinary/neeto-email-notifications-frontend

v2.2.19

Published

A repo acts as the source of truth for the new nano's structure, configs, data etc.

Downloads

881

Readme

neeto-email-notifications-nano

The neeto-email-notifications-nano is a comprehensive email notification management solution designed for the Neeto ecosystem. Implemented as a Ruby on Rails engine with associated React frontend components (@bigbinary/neeto-email-notifications-frontend), it provides a unified interface for managing email notifications across neeto applications.

Table of Contents

  1. Installation (Backend Engine)
  2. Configuration (Backend Engine)
  3. Frontend Integration
  4. Core Concepts
  5. Usage Examples
  6. API Endpoints
  7. Liquid Template Variables
  8. Email Validation
  9. Incineration Concern
  10. Development Environment Setup
  11. Testing & Debugging
  12. Publishing

Installation (Backend Engine)

Follow these steps to integrate the neeto-email-notifications-engine into your host Rails application:

1. Add the Gem

Add the gem to your application's Gemfile:

# Gemfile
source "NEETO_GEM_SERVER_URL" do
  gem "neeto-email-notifications-engine"
end

2. Install Gems

Run bundler to install the gem and its dependencies:

bundle install

3. Install Migrations

Add required migrations in the db/migrate folder. Run the following commands to generate the migrations.

bundle exec rails g neeto_email_notifications_engine:install

This will generate the migration to create the neeto_email_notifications_engine_email_notifications table, which holds the data for the email notifications, and have custom_fields column to include custom attributes.

4. Run Migrations

Apply the migrations to your database:

bundle exec rails db:migrate

5. Mount the Engine

Add the engine's routes to your application's config/routes.rb:

# config/routes.rb
mount NeetoEmailNotificationsEngine::Engine, at: "/neeto_email_notifications"

NOTE: The mount point & base URL must be /neeto_email_notifications and cannot be changed to any other path.

Note: The engine uses the liquid gem for template rendering. This will be installed automatically as a dependency.

Configuration (Backend Engine)

1. Initializer Setup

Create an initializer file config/initializers/neeto_email_notifications_engine.rb to configure the engine:

# config/initializers/neeto_email_notifications_engine.rb
NeetoEmailNotificationsEngine.configure do |config|
  # IMPORTANT: Configure which model types can hold email notifications.
  # This configuration is MANDATORY for the engine to work properly.
    config.allowed_notification_holder_types = ["PaymentPlan", "SomeOtherModel"]
end

The allowed_notification_holder_types configuration is mandatory. Failing to configure this will result in validation errors when creating email notifications.

2. Models

NeetoEmailNotificationsEngine::EmailNotification (source code)

Key Associations:

belongs_to :notification_holder, polymorphic: true
has_rich_text :message

Key Validations:

  • notification_holder_type must be in the configured allowed_notification_holder_types.
  • subject, message are required when is_enabled is true.
  • send_from must be a valid email format when required.
  • All email fields (notify_emails, notify_cc_emails, notify_bcc_emails) are validated for proper email format.

Available Methods:

  • message_body_content: Returns HTML content of the rich text message.
  • custom_field_key: Abstract method that subclasses must implement.
  • notification_type: Returns the notification type from custom fields.
  • disabled_by_user?: Checks if the notification was disabled by user action.

Setting Up Host Application Models

Ensure the models specified in allowed_notification_holder_types have the correct associations defined:

Single Notification Per Model (Most Common)

# app/models/form.rb
class Form < ApplicationRecord
  # Standard single notification association
  has_one :email_notification, as: :notification_holder,
    class_name: "::NeetoEmailNotificationsEngine::EmailNotification", dependent: :destroy

  # Optional: Create default notification after model creation
  after_create :seed_email_notification

  private

    def seed_email_notification
      self.create_email_notification!(
        send_from: Rails.application.secrets.mailer[:default_from_email],
        notify_emails: [],
        is_enabled: false,
        subject: "New {{form-name}} submission",
        message: "A new submission has been received for {{form-name}}."
      )
    end
end

Multiple Notification Types Per Model

# app/models/meeting.rb
class Meeting < ApplicationRecord
  # General association for all notifications
  has_many :email_notifications, as: :notification_holder,
    class_name: "::NeetoEmailNotificationsEngine::EmailNotification", dependent: :destroy

  # Specific notification types using custom fields
  has_one :reminder_notification,
    -> { where("custom_fields -> 'notification_type' ? :value", value: "reminder") },
    as: :notification_holder, class_name: "::NeetoEmailNotificationsEngine::EmailNotification"

  has_one :confirmation_notification,
    -> { where("custom_fields -> 'notification_type' ? :value", value: "confirmation") },
    as: :notification_holder, class_name: "::NeetoEmailNotificationsEngine::EmailNotification"

  has_one :cancellation_notification,
    -> { where("custom_fields -> 'notification_type' ? :value", value: "cancellation") },
    as: :notification_holder, class_name: "::NeetoEmailNotificationsEngine::EmailNotification"

  after_create :setup_default_notifications

  private

    def setup_default_notifications
      create_reminder_notification!(
        send_from: "[email protected]",
        subject: "Reminder: {{meeting-title}} starts in 1 hour",
        message: "Your meeting {{meeting-title}} is scheduled to start in 1 hour.",
        custom_fields: { notification_type: "reminder" },
        is_enabled: false
      )

      create_confirmation_notification!(
        send_from: "[email protected]",
        subject: "Meeting Confirmed: {{meeting-title}}",
        message: "Your meeting {{meeting-title}} has been confirmed for {{meeting-date}}.",
        custom_fields: { notification_type: "confirmation" },
        is_enabled: true
      )
    end
end

Creating Custom Notification Models

# app/models/submission_email_notification.rb
class SubmissionEmailNotification < ::NeetoEmailNotificationsEngine::EmailNotification
  # Scope to only submission notifications
  default_scope { where("custom_fields -> 'notification_type' ? :value", value: "submission") }

  after_initialize :set_notification_type

  def custom_field_key
    "notification_type"
  end

  private

    def set_notification_type
      self.custom_fields ||= {}
      self.custom_fields[custom_field_key] = "submission"
    end
end

# Usage in host model
class Form < ApplicationRecord
  has_one :submission_email_notification, as: :notification_holder, dependent: :destroy

  # You can still have the general association too
  has_one :email_notification, as: :notification_holder,
    class_name: "::NeetoEmailNotificationsEngine::EmailNotification", dependent: :destroy
end

Database Schema Information The engine creates a table neeto_email_notifications_engine_email_notifications with these key columns:

  • notification_holder_type & notification_holder_id: Polymorphic association.
  • notify_emails: Array of recipient email addresses.
  • notify_cc_emails & notify_bcc_emails: Arrays for CC and BCC recipients.
  • send_from: Sender email address.
  • subject: Email subject (supports Liquid templates).
  • message: Rich text message content (supports Liquid templates).
  • is_enabled: Boolean flag to enable/disable notifications.
  • custom_fields: JSONB column for additional metadata.
  • reply_to_id: Optional reference for reply-to configuration.
  • type: String column for Single Table Inheritance (STI) support.

Default Attributes Class Method

Important: Host applications must define the default_attributes class method in their custom notification models that inherit from NeetoEmailNotificationsEngine::EmailNotification. This method is required and will receive the notification_holder as a parameter. This method should return a hash with the default attributes for the email notification.

Variables in the subject and message must always be wrapped like this:

<span data-variable data-label="label" data-id="key">{{key}}</span>

Example Implementation

def self.default_attributes(quiz)
  {
    send_from: Rails.application.secrets.mailer[:default_from_email],
    notify_emails: [quiz.user.email],
    is_enabled: true,
    subject: "A new submission has arrived for {{quiz-name}}",
    message: <<~HTML.squish
      <b><span data-variable data-label="Quiz name" data-id="quiz-name">{{quiz-name}}</span></b>
      has a new submission.<br/><br/>
      <span data-variable data-label="All answers" data-id="all-answers">{{all-answers}}</span>
    HTML
  }
end

Frontend Integration

1. Install Frontend Package

yarn add @bigbinary/neeto-email-notifications-frontend

This package will provide a single component NeetoEmailNotification, which uses components from neeto-molecules.

2. Install Peer Dependencies

If the host app doesn't already include these peer dependencies, install them:

# DO NOT INSTALL THE EXACT VERSIONS MENTIONED BELOW AS THEY MIGHT BE OUTDATED.
# ALWAYS PREFER INSTALLING THE LATEST COMPATIBLE VERSIONS.
yarn add @babel/runtime@^7.26.10 @bigbinary/neeto-cist@^1.0.17 @bigbinary/neeto-commons-frontend@^4.13.43 @bigbinary/neeto-editor@^1.47.16 @bigbinary/neeto-filters-frontend@^4.3.21 @bigbinary/neeto-icons@^1.20.49 @bigbinary/neeto-molecules@^3.16.63 @bigbinary/neetoui@^8.3.9 @honeybadger-io/js@^6.10.1 @honeybadger-io/react@^6.1.25 @tailwindcss/container-queries@^0.1.1 @tanstack/react-query@^5.59.20 @tanstack/react-query-devtools@^5.59.20 antd@^5.22.0 axios@^1.8.2 buffer@^6.0.3 classnames@^2.5.1 crypto-browserify@^3.12.1 dompurify@^3.2.4 formik@^2.4.6 https-browserify@^1.0.0 i18next@^22.5.1 js-logger@^1.6.1 mixpanel-browser@^2.47.0 os-browserify@^0.3.0 path-browserify@^1.0.1 qs@^6.11.2 ramda@^0.29.0 react@^18.3.1 react-dom@^18.3.1 react-helmet@^6.1.0 react-i18next@^12.3.1 react-router-dom@^5.3.3 react-toastify@^8.0.2 source-map-loader@^4.0.1 stream-browserify@^3.0.0 stream-http@^3.2.0 tailwindcss@^3.4.14 tty-browserify@^0.0.1 url@^0.11.0 util@^0.12.5 vm-browserify@^1.1.2 yup@^0.32.11 zustand@^4.4.2

Note: Carefully manage potential version conflicts with your host application.

3. Components

NeetoEmailNotificationForm (source code)

Props

| Prop | Type | Default | Description | | ------------------------- | --------- | -------------------------------------------------------- | ---------------------------------------------------------------- | | emailNotificationParams | Object | {} | Required. Parameters for fetching email notification data | | title | String | "Email notification" | Title displayed above the notification toggle | | notificationToggleLabel | String | "Send an email notification when a new event occurred" | The label displayed beside the notification toggle switch | | disabled | Boolean | false | Disables the entire component | | onSuccess | Function | noop | Callback function triggered after successful notification update | | breadcrumbs | Array | [] | Breadcrumb navigation data | | children | ReactNode | undefined | Additional content rendered when notifications are enabled | | blockNavigation | Boolean | false | Shows block navigation alert for unsaved changes | | helpPopoverProps | Object | {} | Props for the help popover component | | tooltipProps | Object | {} | Props for tooltip shown when component is disabled | | emailFormProps | Object | {} | Props passed to the underlying EmailForm component | | emailFormikProps | Object | {} | Props passed to the EmailFormProvider component | | emailPreviewProps | Object | {} | Props passed to the EmailPreview component | | fieldsVisibility | Object | {} | Controls which fields are visible in the email form |

FieldsVisibility

Default visibility for each field is as follows:

{
  showSendToField: true,
  showReplyToField: false,
  showSendToAsRadio: false,
  showCcField: false,
  showBccField: false,
}

You can override any of these by passing a fieldsVisibility prop with your desired values.

emailNotificationParams Object Structure

{
  notificationHolderId: "uuid-string",      // ID of the notification holder
  notificationHolderType: "Form",           // Type of the notification holder
  customFields: {                           // Optional custom fields for filtering
    notificationType: "submission"          // Example: different notification types
  }
}

Usage Example

import React from "react";
import { NeetoEmailNotificationForm } from "@bigbinary/neeto-email-notifications-frontend";

const FormSettingsPage = ({ formId }) => {
  const handleNotificationUpdate = () => {
    console.log("Email notification updated successfully!");
  };

  return (
    <NeetoEmailNotificationForm
      title="Form Submission Notification"
      notificationToggleLabel="Get notified when someone submits your form"
      emailNotificationParams={{
        notificationHolderId: formId,
        notificationHolderType: "Form",
        customFields: { notificationType: "submission" }
      }}
      emailPreviewProps={{
        formatBody: message => replaceVariablesWithDummyValues(message, values),
      }}
      breadcrumbs={[
        { text: "Forms", link: "/forms" },
        { text: "Settings", link: `/forms/${formId}/settings` }
      ]}
      onSuccess={handleNotificationUpdate}
    />
  );
};

export default FormSettingsPage;

4. Hooks

useFetchEmailNotifications (source code)

Fetches email notification data for a specific notification holder.

import { useFetchEmailNotifications } from "@bigbinary/neeto-email-notifications-frontend";

const { data, isLoading, error } = useFetchEmailNotifications({
  notificationHolderId: "form-uuid",
  notificationHolderType: "Form",
  customFields: { notificationType: "submission" }
});

useUpdateEmailNotification (source code)

Updates email notification settings.

import { useUpdateEmailNotification } from "@bigbinary/neeto-email-notifications-frontend";

const { mutate: updateEmailNotification, isPending } = useUpdateEmailNotification();

const handleUpdate = (notificationData) => {
  updateEmailNotification({
    ...notificationData,
    notificationHolderId: "form-uuid",
    notificationHolderType: "Form"
  });
};

Usage Examples

Creating Custom Notification Models

You can create specialized notification models that inherit from the base EmailNotification class:

class SubmissionEmailNotification < ::NeetoEmailNotificationsEngine::EmailNotification
  default_scope { where("custom_fields -> 'notification_type' ? :value", value: "submission") }

  after_initialize :set_notification_type

  def custom_field_key
    "notification_type"
  end

  private

    def set_notification_type
      self.custom_fields ||= {}
      self.custom_fields[custom_field_key] = "submission"
    end
end

Setting Up Notification Holders

Configure your models to support email notifications:

class Meeting < ApplicationRecord
  has_one :reminder_notification, -> { where("custom_fields -> 'notification_type' ? :value", value: "reminder") },
    as: :notification_holder, class_name: "::NeetoEmailNotificationsEngine::EmailNotification"

  has_one :confirmation_notification, -> { where("custom_fields -> 'notification_type' ? :value", value: "confirmation") },
    as: :notification_holder, class_name: "::NeetoEmailNotificationsEngine::EmailNotification"

  after_create :setup_notifications

  private

    def setup_notifications
      create_reminder_notification!(
        send_from: "[email protected]",
        subject: "Reminder: {{meeting-title}} in 1 hour",
        message: "Your meeting {{meeting-title}} is scheduled to start in 1 hour.",
        custom_fields: { notification_type: "reminder" }
      )

      create_confirmation_notification!(
        send_from: "[email protected]",
        subject: "Meeting Confirmed: {{meeting-title}}",
        message: "Your meeting {{meeting-title}} has been confirmed for {{meeting-date}}.",
        custom_fields: { notification_type: "confirmation" }
      )
    end
end

Seeding Default Email Notification Content

It is recommended to automatically create a default email notification record for each instance of your model. This ensures the notification UI and API always have a record to fetch and update, preventing errors and missing functionality. You can use an after_create callback in your model to seed this record.

Example:
class Quiz < ApplicationRecord
  has_many :email_notifications, as: :notification_holder,
    class_name: "NeetoEmailNotificationsEngine::EmailNotification", dependent: :destroy
  has_one :push_email_notification, as: :notification_holder

  after_create :create_default_email_notification

  private

    def create_default_email_notification
      self.create_push_email_notification!(PushEmailNotification.default_attributes(self))
    end
end

Using the Email Notification Service

Create service classes that include the email notification functionality:

class MeetingReminderService
  include ::NeetoEmailNotificationsEngine::EmailNotificationService

  def initialize(meeting)
    @meeting = meeting
    @email_notification = meeting.reminder_notification
  end

  private

    def send_emails
      return unless @email_notification.is_enabled?

      MeetingMailer.reminder_email(
        recipients: @email_notification.notify_emails,
        cc: @email_notification.notify_cc_emails,
        bcc: @email_notification.notify_bcc_emails,
        subject: @subject,
        message: @message,
        meeting: @meeting
      ).deliver_now
    end

    def load_liquid_parameters
      @liquid_parameters[:text] = {
        "meeting-title" => @meeting.title,
        "meeting-date" => @meeting.scheduled_at.strftime("%B %d, %Y"),
        "meeting-time" => @meeting.scheduled_at.strftime("%I:%M %p")
      }

      @liquid_parameters[:html] = @liquid_parameters[:text]
    end
end

# Usage
meeting = Meeting.find(params[:id])
MeetingReminderService.new(meeting).process

API Endpoints

The engine exposes API endpoints under the configured mount path (default /neeto_email_notifications):

| Method | Path | Description | Parameters | |--------|------|-------------|------------| | GET | /email_notification | Fetch email notification settings | notification_holder_id, notification_holder_type, custom_fields | | PUT | /email_notification | Update email notification settings | notification_holder_id, notification_holder_type, email_notification params |

Example API Usage:

// Fetch notification settings
axios.get('/neeto_email_notifications/email_notification', {
  params: {
    notification_holder_id: 'form-uuid',
    notification_holder_type: 'Form',
    custom_fields: { notification_type: 'submission' }
  }
})

// Update notification settings
axios.put('/neeto_email_notifications/email_notification', {
  notification_holder_id: 'form-uuid',
  notification_holder_type: 'Form',
  email_notification: {
    is_enabled: true,
    subject: 'New form submission',
    message: 'A new submission was received.',
    notify_emails: ['[email protected]'],
    send_from: '[email protected]'
  }
})

Liquid Template Variables

Email subjects and messages support Liquid templating for dynamic content:

# In your notification setup
email_notification.update!(
  subject: "New {{form-name}} submission from {{user-name}}",
  message: "Hello {{admin-name}}, a new submission was received for {{form-name}} on {{submission-date}}."
)

# In your service class
def load_liquid_parameters
  @liquid_parameters[:text] = {
    "form-name" => @form.name,
    "user-name" => @submission.user.name,
    "admin-name" => @form.owner.name,
    "submission-date" => @submission.created_at.strftime("%B %d, %Y")
  }

  @liquid_parameters[:html] = @liquid_parameters[:text]
end

Development Environment Setup

Instructions for Development

Check the Frontend package development guide for step-by-step instructions to develop the frontend package.

Backend Development

  1. Rails Server: Start the main application

    bundle exec rails server
  2. Database Setup: Ensure migrations are run

    bundle exec rails db:migrate
  3. Testing: Run the test suite

    bundle exec rails test

Testing & Debugging

Test Helpers

The engine provides factories for testing:

# Use in your tests
FactoryBot.create(:neeto_email_notification_engine_email_notification,
  notification_holder: your_model_instance
)

Use the test/dummy app within the engine's repository for isolated testing.

Publishing

For instructions on building and releasing the @bigbinary/neeto-email-notifications-frontend NPM package and the neeto-email-notifications-engine Ruby gem, please refer to the internal guide: Building and Releasing Packages.