jeudi 28 avril 2022

JavaScript Design Patterns - Method which behaves as a manager and call different methods

Introduction

I have different features in my app, like:

  1. Reset password (forgot password)
  2. Update user password
  3. Sign up
  4. Become premium

For each feature, when success, I want to send a custom HTML email to the user.

Generation of the emails

As the HTML main structure is the same (only the content (texts) changes), I have decided to implement my helper method generateEmailTemplate():

const { HEAD, BODY } = require("../utils");

module.exports = (main) => `
  <!DOCTYPE html>
  <html lang="en">
    ${HEAD}
    ${BODY(main)}
  </html>
`;

And, in order to include the specific data to the generated template, I am using different methods for each feature:

const signUpWelcomeEmailTemplate = (name) => 
  templateGenerator(`<p>Welcome, ${name}</p>`);

const premiumEmailTemplate = (name) =>
  templateGenerator(`<h1>${name}, you are now premium!</h1>`); 

// The html is more complex, I have reduced it for simiplicity

Sending emails

In order to send the emails to the users, I have the following method, which adds an email record to my database. Then, when the record is added, a custom extension connected to the MailGun service sends the mail via SMTP.

This is the implementation of my method:

async function sendEmail(
  to,
  subject,
  text = undefined,
  html = undefined
) {
  const mailsRef = db.collection("mails");

  const mail = {
    to,
    message: {
      subject,
      ...text && { text },
      ...html && { html },
    },
  };

  await mailsRef.add(mail);

  functions.logger.log("Queued email for delivery!");
};

Problem

Now, in order to use this method, in each feature, I have to do the following:

async function goPremium(user) {
   try {
     await purchasePremium(user.uid);

     const html = premiumEmailTemplate(user.name);

     sendEmail(user.email, "Premium purchase success!", undefined, html);
   } catch(err) {
     ...
   }
}

I am looking for a pattern which generalizes this call, I mean, some kind of email manager.

I have thought about two different ways to refactor this code:

#1 (I don't like this way, as the method might be super long, I mean, imagine 100 features...)

   function emailManager(user, type) {
     switch(type) {
       "welcome":
         sendEmail(user.email, "Welcome!", undefined, welcomeEmailTemplate(user.name));
         break;

       "premium":
         sendEmail(user.email, "Premium purchase success!", undefined, premiumEmailTemplate(user.name));
         break;

       default:
         break;
     }
   }
  1. Just create different methods and export them from a 'central' module.
...

const sendPremiumEmail = (user) => {
  const title = "Premium purchase success!";
  const html = premiumEmailTemplate(user.name);
  
  return sendEmail(user.email, title, undefined, html);
};

...

module.exports = {
  sendWelcomeEmail,
  sendPremiumEmail,
  ...
}

But... maybe there is another way, a pattern which exactly solves this situation. Any ideas?

Aucun commentaire:

Enregistrer un commentaire