'ics description ignores everything after #(hash) symbol - ics.js

we need to generate and download ics file in JavaScript with dynamic data.

The problem is that when users use #(hashtag) symbol in the description, everything after the symbol is ignored/disappears.

For example if user uses this description:

some #descripiton test #2

the generated(downloaded) ics file will only show this:

some

Here is the full code:

// trigger ics generation/download
<div className="meetupIcon"
     onClick={() => {
     const event = createEventStringOutlookDate();
     window.open(`data:text/calendar;charset=utf8,${escapeHtml(event)}`);
     }}
>

const createEventStringOutlookDate = () => {

    let participantsArray = [];

    if(meetup.closedParticipants.length>0) {
      let closedParticipantsArray = meetup.closedParticipants.split(',');
      closedParticipantsArray.forEach(participant => participantsArray.push({email: participant}))
    }

    const newEvent = createEvent({
      id: meetup.id,
      name: meetup.name,
      startDate: meetup.startDate,
      endDate: meetup.endDate,
      attendees: participantsArray,
      type: meetup.eventType,
      website: meetup.website,
      address: meetup.address,
      // city: meetup.city,
      // country: meetup.country,
      description: meetup.description,
      meetupAll: meetup,
    });
    
    const textArray = newEvent.split("\n").filter((f) => f.trim() !== "");
    
    const event = textArray.join("\n");

    // ITS STILL FINE HERE!
    console.log('FINAL VERSION OF EVENT', escapeHtml(event))

    return event;
  };

export const escapeHtml = text => {
  let map = {
    "<": "&lt;",
    ">": "&gt;",
  };

  return text.replace(/[<>]/g, function(m) {
    return map[m];
  });
};

const ics = require("ics");
export const createEvent = meetup => {
  ... 
  inviteText = `
    ${meetup.description && meetup.description}
    ...`
return ics.createEvent(
    {
      title: escape(title),
      description: inviteText,
      busyStatus: "BUSY",
      location: `${location}`,
      start: [
        startDate.getFullYear(),
        startDate.getMonth() + 1,
        startDate.getDate(),
        startDate.getHours(),
        startDate.getMinutes()
      ],
      end: [
        endDate.getFullYear(),
        endDate.getMonth() + 1,
        endDate.getDate(),
        endDate.getHours(),
        endDate.getMinutes()
      ],
      // duration: { minutes: duration },
      attendees: meetup.attendees,
      alarms: alarms
    },
    (error, value) => {
      if (error) {
        console.log(error);
      }
      return value;
    }
  );
};

In the final console.log before download, everything is fine:

FINAL VERSION OF EVENT 

BEGIN:VCALENDAR
VERSION:2.0
CALSCALE:GREGORIAN
PRODID:adamgibbons/ics
METHOD:PUBLISH
X-PUBLISHED-TTL:PT1H
BEGIN:VEVENT
UID:e5b9fa42-9d67-4a83-b7b3-98f7f3537ca4
SUMMARY:face%20%232%20face%20%23%20test%20event
DTSTAMP:20220407T090447Z
DTSTART:20220407T020000Z
DTEND:20220430T030000Z
DESCRIPTION:\nsome #descripiton test #2\n\nRegistration required: No\n\nCos
    t: Free\n\nInternal event\n
X-MICROSOFT-CDO-BUSYSTATUS:BUSY
BEGIN:VALARM
ACTION:AUDIO
REPEAT:1
DESCRIPTION:Reminder
ATTACH;VALUE=URI:Glass
TRIGGER:-PT15M
END:VALARM
END:VEVENT
END:VCALENDAR

But we get this in the downloaded version, notice the lack of everthing after the # symbol in the description field:

BEGIN:VCALENDAR
VERSION:2.0
CALSCALE:GREGORIAN
PRODID:adamgibbons/ics
METHOD:PUBLISH
X-PUBLISHED-TTL:PT1H
BEGIN:VEVENT
UID:f88a4516-62ff-443a-aba6-8010c43cf534
SUMMARY:face #2 face # test event
DTSTAMP:20220407T083212Z
DTSTART:20220407T020000Z
DTEND:20220430T030000Z
DESCRIPTION:\nsome


Solution 1:[1]

I ended up replacing every # with '%23' and it seems to work fine:

inviteText = replaceAll(inviteText, '#', '%23');

function replaceAll(str, find, replace) {
  return str.replace(new RegExp(find, 'g'), replace);
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 failedCoder