Action

Weekly/Monthly event : prep notes

Posted by Ro136, Last update over 1 year ago

Instructions

purpose of the action

This action’s original inspiration is to keeps notes throughout the week or month, for a regular meeting or event.

For example if you remember updates to share, or questions to ask in your upcoming weekly meeting, this action will organize them all into 1 draft(“log draft”) for you.

It will also create a reminder for 10 minutes before the next event. The reminder will have a link that opens the “log draft”, so you don’t need to go looking for your draft during the meeting

a little more detail

How it works
How to use the action is very similar to the “add to list” action by @agiletortoise, but for Regularly occurring events.

Tap the action, select a event that you have previously set, and the action will automatically store your draft content to a “log draft”

Instead of a constant list, this action will keep a running note for each upcoming event
e.g. monthly, bi-monthly meetings, events every xx days, etc.)

1 log draft per each event
It is a “log draft” for each meeting.
So the 1st time you use it, it will create a new log draft and add the current text.

For example, for a weekly meeting on Monday at 9:00, it will append the current draft to the same “log draft” until Monday at 9:00, with a time stamp.
After Monday 9:00, it will create a new “log draft” again for the next Monday’s meeting notes and so on.

Time stamp
The time stamp is set to the last edit date of the current draft.
This is so, if you write a note down, but forget to use the action, it will still show when you last wrote down your notes

customization

I’ve made it so you can customize most of the action from 4 “template tags” steps.
This is so you don’t need to know the JavaScript code to do most of the customizations.

Instructions for customizing 4 template tags

1st template tag : category

Set your events in this 1st template tag.
There are examples set by default, but please feel free to change these based on your needs.

This is maybe the most difficult part, but you only need to set this once, and I promise it’s not too bad if you follow the instructions below, so please bare with me…

There are 4 types of dates this action can calculate for
Here are 4 examples

  1. “Weekly” : e.g. a meeting, every Monday at 9:00
  2. “Monthly (date)” : e.g. a self evaluation, on the 11th, 21st & 31st of every month, at 21:00
  3. “Monthly (weekday)” : e.g. an event, every 2nd & 4th Mondays at 13:00. Or a monthly seminar, on the 1st Thursday of the month, at 17:00(Works for once a month or multiple)
  4. “Every xx days” : e.g. shopping list every 10 days, at 11:00, from Jul 25 2022

These 4 examples will be inputted as the following
Please keep reading to see how to set the template

meeting % mon % 9:00 % weekly
Self evaluation % 11:21:31 % 21:00 % date
event % Monday % 13:00 % month % 2:4
seminar % Thu % 17:00 % month % 1
shopping list % jul 25 2022 % 11:00 % days % 10

Separate with “%”

#1 weekly

“title% day of the week% time of event% type=weekly”

  • title = any name, but do not use %
  • day of the week = 3 letters or full weekday name, not case sensitive (e.g. monday, Monday, MONDAY, MON, mon)
  • time of event = 24 hour formatted time (“:” needed to separate hh:mm)
  • type = “weekly”

Example #1 would become
“Meeting 1% monday% 9:00% weekly”

#2 same date of every month

“title% dates:date% time of event% type=date”

  • title = any name, but do not use %
  • dates = dates of the month, separated by “:” for multiple (e.g. 1:15:30 for 1st, 15th, and the 30th)
  • time of event = 24 hour formatted time (“:” needed to separate hh:mm)
  • type = “date”

Example #2 would become
“Self evaluation% 11:21:31% 21:00% date”

#3 the xth weekday of every month

“title% weekday% time of event% type=month”% frequency(xth weekday)

  • title = any name, but do not use %
  • day of the week = 3 letters or full weekday name, not case sensitive (e.g. monday, Monday, MONDAY, MON, mon)
  • time of event = 24 hour formatted time (“:” needed to separate hh:mm)
  • type = “month”
  • frequency : the xth weekday of the month(e.g. every 1st and 3rd Sundays will be “1:3”)

Example #3 would become
event % Monday % 13:00 % month % 2:4
and
seminar % Thu % 17:00 % month % 1

#4 every xx days from a certain date

“title% date of 1st event% time of event% type=days”% frequency(every xx day)

  • title = any name, but do not use %
  • date of 1st event = the date of the first event to count from in the following format “mmm dd yyyy” (e.g. jul 25 2022)
  • time of event = 24 hour formatted time (“:” needed to separate hh:mm)
  • type = “days”
  • frequency : every xx days(e.g. every 15days will be “15”)

Example #4 would become
shopping % jul 25 2022 % 11:00 % days % 10

2nd template tag : appendTitle

Here you can set part of the title

All log draft’s start with the following 2 lines
“# [[EventTitle]] + [[appendTitle]]”
“## Date(WWW MMM DD YYYY)”

Event title = The title you input on the 1st template tag\
appendTitle = anything you input in the 2nd template tag

For example,
If 2nd template tag is “ : prep notes”
And there is a “Meeting” on Aug 1
It will show as…
“# Meeting : prep notes”
“## Mon Aug 01 2022”

By default the template tag is set to “ : prep notes”

3rd template tag : tagPreset

This action will assign #prep-notes to the log Draft
If you want to add any other tags, write them here
If there are multiple, add them here by separating the lines

This step is blank by default

4th template tag : reminderList

This last template tag will set the reminders list to use
Reminder lists are like folders for the reminders app

Because the action creates a reminder for your log draft, it need to know where to put the reminder.
Set this to whatever list you want the reminder to be created in.

By default it is set to “PrepNotes”

Steps

  • defineTemplateTag

    name
    category
    template
    meeting % mon % 9:00 % weekly
    Self evaluation % 11:21:31 % 21:00 % date
    event % Monday % 13:00 % month % 2:4
    seminar % Thu % 17:00 % month % 1
    shopping list % jul 25 2022 % 11:00 % days % 10
  • defineTemplateTag

    name
    appendTitle
    template
     : prep notes
  • defineTemplateTag

    name
    tagPresets
    template
  • defineTemplateTag

    name
    reminderList
    template
    PrepNotes
  • script

    // use last edit date as time stamp
    /*
      import defined template tags
    */
    
    // main tag to assign to add drafts
    const listTag = "prep-notes";
    
    // setup categories
    const categories = draft.processTemplate("[[category]]").trim().split("\n");
    
    // text to add to append to title
    const appendTitle = draft.processTemplate("[[appendTitle]]");
    
    // tags to add other than "prep-notes"
    const tags = draft.processTemplate("[[tagPresets]]").trim().split("\n");
    
    // which reminders list to add to
    const list = ReminderList.findOrCreate(draft.processTemplate("[[reminderList]]").trim());
    
    /*
      get current draft, date + create a prompt to choose event from
    */
    // grab current draft
    const currentContent = draft.content.trim();;
    
    // set today
    let today = new Date();
    // also time of draft's last edit as "lastEdit" <- needed because "today" will be modified later
    let lastEdit = new Date(draft.modifiedAt);
    
    // prompt to select a event criteria
    let p = Prompt.create();
    p.title = "Select Event";
    for (var cat of categories) {
    	ca = cat.trim().split(/\s*%\s*/);
        	p.addButton(ca[0], ca)
    }
    
    if (p.show()) { // user made a selection
    	var criteria = p.buttonPressed;
    
    	// grab time of the event
    	let criteriaT = criteria[2].split(/\s*:\s*/);
    	// convert time to value
    	var criteriaHour = Number(criteriaT[0]);
    	var criteriaMin = Number(criteriaT[1]);
    
    	/*
    	  set variables
    	*/
    
    	// find out if current time is before event time
    	var criteriaTime = new Date(today);
    	criteriaTime = new Date(criteriaTime.setHours(criteriaHour, criteriaMin, 0));
    	let eventYet = (today - criteriaTime);
    
    	var yet = false;
    	if (eventYet < 0) {
    		yet = true;
    	}
    	else {
    		yet = false;
    	}
    
    	// template tag week day conversion array
    	var weekday=new Array(7);
    	weekday["sunday"] = 0;
    	weekday["monday"] = 1;
    	weekday["tuesday"] = 2;
    	weekday["wednesday"] = 3;
    	weekday["thursday"] = 4;
    	weekday["friday"] = 5;
    	weekday["saturday"] = 6;
    	weekday["sun"] = 0;
    	weekday["mon"] = 1;
    	weekday["tue"] = 2;
    	weekday["wed"] = 3;
    	weekday["thu"] = 4;
    	weekday["fri"] = 5;
    	weekday["sat"] = 6;
    
    	// set today's time to 12:00:00 to prevent issues with daylight saving time
    		// (any time between 1:00:01 ~ 22:59:59 is ok, but using 12:00:00 for convenience)
    	today = new Date(today.setHours(12, 0, 0));
    
    
    	/*
    	  the key variable for the function
    	  "nextEvent"
    	  is what the upcoming function will return
    	*/
    	var nextEvent = new Date(today);
    
    	var daysTilEvent;
    
    	// set function to get the "nextEvent"
    	function getNextEventDay(title, dayOf, time, type, freq) {
    		// #1 if weekly event
    		if (type == "weekly") {
    			// Current date + dates until next meetingday
    			daysTilEvent =  weekday[dayOf.toLowerCase()] - today.getDay();
    
    			// if today is the same day as event
    			if (daysTilEvent == 0){
    				// find out if it is before the event time
    				// if event not started yet, set event date to today
    				if (yet == true) {
    					nextEvent = new Date(nextEvent.setHours(criteriaHour, criteriaMin, 0));
    				}
    				// if event already started, set event date to next week (+ 7days)
    				else {
    					nextEvent = new Date(nextEvent.setDate(nextEvent.getDate() + 7));
    					nextEvent = new Date(nextEvent.setHours(criteriaHour, criteriaMin, 0));
    				}
    			}
    			// event is next week
    			else if (daysTilEvent < 0){
    				nextEvent = new Date(nextEvent.setDate(nextEvent.getDate() + (daysTilEvent + 7)));
    				nextEvent = new Date(nextEvent.setHours(criteriaHour, criteriaMin, 0));
    			}
    			// event is this week week
    			else {
    				nextEvent = new Date(nextEvent.setDate(nextEvent.getDate() + daysTilEvent));
    				nextEvent = new Date(nextEvent.setHours(criteriaHour, criteriaMin, 0));
    			}
    		}
    		// #2 if event is a date of every month
    		else if (type == "date") {
    			let eventDates = dayOf.split(/\s*:\s*/);
    			eventDates = eventDates.map(str => {
    				return Number(str);
    			});
    			for (let eventDate of eventDates) {
    				daysTilEvent = eventDate - today.getDate();
    				
    				// if today is the event date and before the event time
    				if ((daysTilEvent == 0) && (yet == true)) {
    					nextEvent = new Date(nextEvent.setDate(eventDate));
    					break;
    				}
    
    				// if today is not the event date
    				nextEvent = new Date(nextEvent.setDate(eventDate));
    
    				// end loop the first time nextEvent > today
    				if (daysTilEvent > 0) {
    					break;
    				}
    			}
    
    			// if loop is complete, but "daysTilEvent" is still < 0
    			// or if today is the date & it is the last day of the array & it is not the time for the event yet
    			// the "nextEvent" will be the first date of the array in the next month
    			if ((daysTilEvent < 0) || ((daysTilEvent == 0) && (nextEvent.getDate() == eventDates[eventDates.length - 1]) && (yet == false))) {
    				// set date to 1, to avoid issues of (Jan 31 + month) -> (Feb 31 = Mar3)
    				nextEvent = new Date(nextEvent.setDate(1))
    				// now set to the 1st occurence next month
    				nextEvent = new Date(nextEvent.setMonth(nextEvent.getMonth() + 1))
    				nextEvent = new Date(nextEvent.setDate(eventDates[0]))
    			}
    			nextEvent = new Date(nextEvent.setHours(criteriaHour, criteriaMin, 0));
    		}
    		// if event is a weekday of every month
    		else if (type == "month") {
    			// convert weekday string to value
    			let wk =  weekday[dayOf.toLowerCase()];
    
    			// split occurence and convert to value
    			let eventDates = freq.split(/\s*:\s*/);
    			eventDates = eventDates.map(str => {
    				return Number(str);
    			});
    			
    			// define new date for upcoming "getDays" function
    			const dte = new Date(today);
    			var specifiedDays
    
    			// set function to list up all of the weekdays in the month
    			function getDays(dt, dy) {
    				const yr = dt.getFullYear();
    				const mth = dt.getMonth();
    				
    				const dys = [];
    				
    				for (let i = 1; i <= 31; i++) {
    					const tmpDate = new Date(yr, mth, i, 12, 0, 10);
    					
    					// end at last day of month
    					if (mth !== tmpDate.getMonth()) break;
    					// ignore unspecified weekdays
    					if (tmpDate.getDay() !== dy) continue;
    				
    					dys.push(tmpDate);
    				}	
    				return dys;
    			}
    
    			// set function to filter the weekdays
    			function filterDays(dt, dy) {
    				const weeks = eventDates;
    				const days = getDays(dt, dy);
    				specifiedDays = days.filter((v, i) => weeks.includes(i+1));
    			}
    			
    			// run funtions to find specified weekdays
    			filterDays(dte, wk);
    			
    			// find the next specifiedDay from today
    			for (let specifiedDay of specifiedDays) {
    				nextEvent = specifiedDay;
    				// stop on first day after today, or today but before event
    				if ((specifiedDay - today > 0) || (specifiedDay - today == 0 && (yet == true))) {
    					break;
    				}
    			}
    			daysTilEvent = nextEvent.getDate() - today.getDate();
    			var dtNextM = new Date(today);
    
    			// if loop is complete but daysTilEvent < 0, or it was today but the time is already after the event
    			if ((daysTilEvent < 0) || ((daysTilEvent == 0) && (nextEvent == specifiedDays[specifiedDays.length - 1]) && (yet == false))) {
    				// set "dtNextM" to a date next month
    				// set date to 1, to avoid issues (Jan 31 + 1 month) -> (Feb 31 = Mar3)	
    				dtNextM = new Date(dtNextM.setDate(1));
    				dtNextM = new Date(dtNextM.setMonth(dtNextM.getMonth() + 1));
    
    				// run the function again for next month
    				filterDays(dtNextM, wk);
    
    				nextEvent = new Date(specifiedDays[0]);			
    			}
    
    			nextEvent = new Date(nextEvent.setHours(criteriaHour, criteriaMin, 0));
    		}
    		// if event is every xx days
    		else if (type == "days") {			
    			let startDate = new Date(dayOf);
    
    			// to avoid issues with daylight saving time
    			startDate = new Date(startDate.setHours(12, 0, 0)) 
    					
    			// get how many days have passed from the start date
    			var daysFromStart = Math.round((today - startDate) / 1000 / 60 / 60 /24);
    			
    			// calculate daysTilEvent
    			daysTilEvent = freq - (daysFromStart - (Math.floor(daysFromStart / freq) * freq));
    			
    			nextEvent = new Date(nextEvent.setDate(nextEvent.getDate() + daysTilEvent));
    			
    			// if the event is today, but hasn't happened yet set the date to today
    				// the calculation above is not able to find today
    			if ((daysTilEvent == freq) && (yet == true)) {
    				nextEvent = new Date(today);
    			}
    			// Set the "nextEvent" time to the actual event time
    			nextEvent = new Date(nextEvent.setHours(criteriaHour, criteriaMin, 0));
    		}
    	}
    
    	/*
    	  run the function to calculate "nextEvent"
    	*/
    	getNextEventDay.apply(null, criteria);
    
    
    	/*
    	  query for list drafts...
    	*/
    	let drafts = Draft.query(criteria[0] + appendTitle, "inbox", [listTag]);
    	// loop over found drafts looking for a matching list
    	let d;
    	for (let draft of drafts) {
    		if (draft.content.startsWith("# " + criteria[0] + appendTitle + "\n## " + nextEvent.toString().slice(0, 15))) {
    			d = draft;
    		}
    	}
    
    	if ((currentContent.length == 0) && (!d)) {
    		alert("Draft does not exist yet.")
    	}
    	else {
    		if (currentContent.length > 0) {
    			// if we didn't find the list, create it...
    			if (!d) {
    				d = Draft.create();
    				// setting the new draft's title
    				d.content = "# " + criteria[0] + appendTitle + "\n## " + nextEvent.toString().slice(0, 15) + "\n" + "****" + "\n";
    		
    				// create reminder
    				let rem = list.createReminder();
    
    				// add link to draft in reminders
    				var cb = d.permalink;
    				
    				rem.title = criteria[0] + " : " + nextEvent.toString().slice(0, 10);
    				rem.notes = cb;
    				// set the reminder notification time	// change following "10" to change how many minutes before the event you get a reminder
    				let dStr = new Date(nextEvent - (10 * 60 * 1000));
    				rem.dueDate = Date.parse(dStr);
    	
    				rem.update();
    		
    				// tag and update content
    				d.addTag(listTag);
    				for (let tag of tags) {
    					d.addTag(tag);
    				}
    			}
    			// append current draft with the current date and time
    			d.content = d.content + "\n> " + lastEdit.toString().slice(0, 10) + " - " + lastEdit.toString().slice(16, 21) + "\\\n" + currentContent + "\n";
    			d.update();
    		}
    		// launch the updated log draft
    			// if the current draft is empty but the log draft already exists, it will just lanch the draft
    		var dURL = CallbackURL.create();
    		dURL.baseURL = d.permalink;
    		dURL.open();
    	}
    }
    else { // user cancelled prompt
    	context.cancel();
    }

Options

  • After Success Trash
    Notification Info
    Log Level Info
Items available in the Drafts Directory are uploaded by community members. Use appropriate caution reviewing downloaded items before use.