Help

Re: Embed Calendar View in Automation Email?

Solved
Jump to Solution
249 0
cancel
Showing results for 
Search instead for 
Did you mean: 
Kiersten_Kollin
6 - Interface Innovator
6 - Interface Innovator

Is it possible to embed a calendar view in an automated email?

1 Solution

Accepted Solutions
Sho
11 - Venus
11 - Venus

I don't know if this will match your use case, but you can use this script in automation to output calendar HTML.

Spoiler

Code:

const { month, year, recordIds } = input.config();

// Please specify the table name
const tableName = "table name"; 

// Caption format for year and month
const caption = `${year} / ${month}`; 

// Whether to link to records true or false
const recordLink = true; 

// URL up to tbl~ or viw~
const linkURL = "https://airtable.com/app~/tbl~/viw~"; 

// Common style
const style = "border:1px solid #ddd; padding:4px; width: 14.2857%; min-height:100px;";

function generateCalendar(year, month, records) {
  const firstDay = new Date(year, month - 1, 1);
  const lastDay = new Date(year, month, 0);
  const daysInMonth = lastDay.getDate();

  let calendarHTML = `<h3 style="text-align:center;">${caption}</h3><table>`;
  calendarHTML += '<tr><th style="width: 14.2857%">Sun</th><th style="width: 14.2857%">Mon</th><th style="width: 14.2857%">Tue</th><th style="width: 14.2857%">Wed</th><th style="width: 14.2857%">thu</th><th style="width: 14.2857%">Fri</th><th style="width: 14.2857%">Sat</th></tr>';
  calendarHTML += '';

  let dayCounter = 1;
  for (let i = 0; i < 6; i++) {
    calendarHTML += '<tr>';
    let bgColor = "#ffffff";
    for (let j = 0; j < 7; j++) {
      if (j === 0 || j === 6) {
        bgColor = "#efefef";
      } else {
        bgColor = "#ffffff";
      }
      if (i === 0 && j < firstDay.getDay()) {
        // Empty cells before the first day of the month
        calendarHTML += `<td style="${style} background-color:${bgColor};"></td>`;
      } else if (dayCounter <= daysInMonth) {
        const cellDate = new Date(year, month - 1, dayCounter);
        const matchingRecords = records.filter(record => {
          const recordDate = new Date(record.date);
          return cellDate.toISOString().split('T')[0] === recordDate.toISOString().split('T')[0];
        });

        const cellContent = matchingRecords.map(record => {
          let content = '<span style="display: inline-block; height: 100%; overflow: hidden; text-overflow: clip; border:1px solid #ddd;">';
          if(recordLink === true){
            content += `<a href="${linkURL}/${record.id}?blocks=hide&date=${record.date}&mode=month">${record.name}</a></span><br>`;
          } else {
            content += `${record.name}</span><br>`;
          }
          return content;
        });
        calendarHTML += `<td style="${style} background-color:${bgColor};">${dayCounter}<br>`;
        calendarHTML += cellContent.join(``);
        calendarHTML += "</td>";
        dayCounter++;
      } else {
        calendarHTML += `<td style="${style} background-color:${bgColor};"></td>`; // Empty cells after the last day of the month
      }
    }
    calendarHTML += '</tr>';
  }

  calendarHTML += '</table>';
  return calendarHTML;
}

const genYear = parseInt(year, 10);
const genMonth = parseInt(month, 10);

// Filtering by specified year and month
const queryRecords = await base.getTable(tableName).selectRecordsAsync({
  recordIds: recordIds
});
let records = queryRecords.records.map(record => {
  let name = record.getCellValueAsString("Name");
  let date = record.getCellValue("Date");
  return {name: name, date: date, id:record.id};
})
const calendarHTML = generateCalendar(genYear, genMonth, records);

// Setting the generated HTML to the 'Calendar' field
output.set('Calendar', calendarHTML);

Automation is set up like this:

2023-12-03 173412.png

Preview:

2023-12-03 174355.png

See Solution in Thread

1 Reply 1
Sho
11 - Venus
11 - Venus

I don't know if this will match your use case, but you can use this script in automation to output calendar HTML.

Spoiler

Code:

const { month, year, recordIds } = input.config();

// Please specify the table name
const tableName = "table name"; 

// Caption format for year and month
const caption = `${year} / ${month}`; 

// Whether to link to records true or false
const recordLink = true; 

// URL up to tbl~ or viw~
const linkURL = "https://airtable.com/app~/tbl~/viw~"; 

// Common style
const style = "border:1px solid #ddd; padding:4px; width: 14.2857%; min-height:100px;";

function generateCalendar(year, month, records) {
  const firstDay = new Date(year, month - 1, 1);
  const lastDay = new Date(year, month, 0);
  const daysInMonth = lastDay.getDate();

  let calendarHTML = `<h3 style="text-align:center;">${caption}</h3><table>`;
  calendarHTML += '<tr><th style="width: 14.2857%">Sun</th><th style="width: 14.2857%">Mon</th><th style="width: 14.2857%">Tue</th><th style="width: 14.2857%">Wed</th><th style="width: 14.2857%">thu</th><th style="width: 14.2857%">Fri</th><th style="width: 14.2857%">Sat</th></tr>';
  calendarHTML += '';

  let dayCounter = 1;
  for (let i = 0; i < 6; i++) {
    calendarHTML += '<tr>';
    let bgColor = "#ffffff";
    for (let j = 0; j < 7; j++) {
      if (j === 0 || j === 6) {
        bgColor = "#efefef";
      } else {
        bgColor = "#ffffff";
      }
      if (i === 0 && j < firstDay.getDay()) {
        // Empty cells before the first day of the month
        calendarHTML += `<td style="${style} background-color:${bgColor};"></td>`;
      } else if (dayCounter <= daysInMonth) {
        const cellDate = new Date(year, month - 1, dayCounter);
        const matchingRecords = records.filter(record => {
          const recordDate = new Date(record.date);
          return cellDate.toISOString().split('T')[0] === recordDate.toISOString().split('T')[0];
        });

        const cellContent = matchingRecords.map(record => {
          let content = '<span style="display: inline-block; height: 100%; overflow: hidden; text-overflow: clip; border:1px solid #ddd;">';
          if(recordLink === true){
            content += `<a href="${linkURL}/${record.id}?blocks=hide&date=${record.date}&mode=month">${record.name}</a></span><br>`;
          } else {
            content += `${record.name}</span><br>`;
          }
          return content;
        });
        calendarHTML += `<td style="${style} background-color:${bgColor};">${dayCounter}<br>`;
        calendarHTML += cellContent.join(``);
        calendarHTML += "</td>";
        dayCounter++;
      } else {
        calendarHTML += `<td style="${style} background-color:${bgColor};"></td>`; // Empty cells after the last day of the month
      }
    }
    calendarHTML += '</tr>';
  }

  calendarHTML += '</table>';
  return calendarHTML;
}

const genYear = parseInt(year, 10);
const genMonth = parseInt(month, 10);

// Filtering by specified year and month
const queryRecords = await base.getTable(tableName).selectRecordsAsync({
  recordIds: recordIds
});
let records = queryRecords.records.map(record => {
  let name = record.getCellValueAsString("Name");
  let date = record.getCellValue("Date");
  return {name: name, date: date, id:record.id};
})
const calendarHTML = generateCalendar(genYear, genMonth, records);

// Setting the generated HTML to the 'Calendar' field
output.set('Calendar', calendarHTML);

Automation is set up like this:

2023-12-03 173412.png

Preview:

2023-12-03 174355.png