From 052bc293eae785fd6405653a6b04c0db28cfaf73 Mon Sep 17 00:00:00 2001
From: Arkerthan <arkerthan@gmail.com>
Date: Mon, 27 Jan 2020 16:36:27 +0100
Subject: [PATCH] rework reminder system

---
 src/Mods/Reminder/reminder.js               | 141 +++++++++++++-------
 src/init/storyInit.tw                       |   2 +-
 src/pregmod/managePersonalAffairs.tw        |  31 +----
 src/uncategorized/BackwardsCompatibility.tw |  15 ++-
 src/uncategorized/endWeek.tw                |   4 -
 src/uncategorized/main.tw                   |  20 +--
 6 files changed, 110 insertions(+), 103 deletions(-)

diff --git a/src/Mods/Reminder/reminder.js b/src/Mods/Reminder/reminder.js
index d4085b8c6b1..e3fdb9d794d 100644
--- a/src/Mods/Reminder/reminder.js
+++ b/src/Mods/Reminder/reminder.js
@@ -1,59 +1,104 @@
-App.Reminders.add = function(entry, week) {
-	let	entries = V.reminders.entries,
-		weeks = V.reminders.weeks,
-		text = V.reminders.text,
-		overdue = V.reminders.overdue;
-
-		text.name = 'text';
-		overdue.name = 'overdue';
-
-	if (entry.length > 0 && week.length > 0 && !isNaN(week)) {
-		if (week <= 0) {
-			if (overdue.length === 0) {
-				overdue.push('');											// for formatting
-			}
-			overdue.push(`${entry} ${App.Reminders.clearButton(overdue)}`);
-		} else {
-			if (text.length === 0) {
-				text.push('');												// for formatting
-			}
-			weeks.push(week);
-			entries.push(entry);
-			text.push(`${entry} in ${numberWithPlural(week, 'week')} ${App.Reminders.clearButton(text)}`);
-		}
+/**
+ * @param {string} message
+ * @param {number} week
+ * @param {string} [category]
+ */
+App.Reminders.add = function(message, week, category = "manual") {
+	if (message === "") { return; }
+	const entry = {message: message, week: week, category: category};
+
+	// V.reminders is sorted by week from low to high, we insert at the correct place so it remains sorted.
+	const index = V.reminders.findIndex(e => e.week >= week);
+	if (index === -1) {
+		V.reminders.push(entry);
+	} else {
+		V.reminders.splice(index, 0, entry);
 	}
 };
 
-App.Reminders.remove = (i, arr) => arr.splice(i, 1);
+/**
+ * @param {number} [maxFuture] how far into the future should reminders be displayed.
+ * @param {string} [category]
+ * @return {string}
+ */
+App.Reminders.list = function({maxFuture = Number.POSITIVE_INFINITY, category = "all"} = {}) {
+	if (V.reminders.length === 0) {
+		return "";
+	}
 
-// App.Reminders.update =
+	/**
+	 * @param {number} index
+	 */
+	let clearEntry = index => { V.reminders.splice(index, 1); };
 
-App.Reminders.clear = function(arr) {
-	arr = [];
-	return arr;
-};
+	function clearOverdue() {
+		V.reminders = V.reminders.filter(e => e.week >= V.week);
+	}
+
+	function clearAll() {
+		V.reminders = [];
+	}
+
+	let r = "";
+
+	let overdue = 0;
+
+	const reminders = category === "all" ? V.reminders : V.reminders.filter(entry => entry.category === category);
+
+	reminders.filter(e => e.week <= V.week + maxFuture)
+		.forEach((entry, index) => {
+			let week;
+			let classes = "";
+			if (entry.week < V.week) {
+				classes = "red";
+				week = `${numberWithPluralOne(-(entry.week - V.week), 'week')} ago`;
+				overdue++;
+			} else if (entry.week === V.week) {
+				classes = "orange";
+				week = "today";
+			} else {
+				if (entry.week <= V.week + 5) {
+					classes = "green";
+				}
+				week = `in ${numberWithPluralOne(entry.week - V.week, 'week')}`;
+			}
+			r += `<div>${entry.message} <span class="${classes}">${week}</span>. ${App.UI.link("Clear", clearEntry, [index], passage())}</div>`;
+		});
+
+	if (overdue > 0) {
+		r += `<div>${App.UI.link("Clear Overdue", clearOverdue, [], passage())}</div>`;
+	}
+	r += `<div>${App.UI.link("Clear All", clearAll, [], passage())}</div>`;
 
-App.Reminders.clearButton = function(arr) {
-	let t = ``;
-	t += `[[Clear|passage()][App.Reminders.remove(${arr.length}, $reminders.${arr.name})${arr.length === 1 && arr[0] === '' ? `, $reminders.${arr.name} = []` : ``}]]`;
-	return t;
+	return r;
 };
 
-App.Reminders.endweek = function() {
-	let entries = V.reminders.entries,
-		weeks = V.reminders.weeks,
-		overdue = V.reminders.overdue,
-		text = [];
-
-	for (let i = 0; i < entries.length; i++) {	// TODO: add index checking to ensure indexes always line up
-		weeks[i]--;
-		if (weeks[i] > 0) {
-			text.push(`${entries[i]} in ${numberWithPluralOne(weeks[i], 'week')}`);
-		} else {
-			overdue.push(`${entries[i]} ${App.Reminders.clearButton(overdue)}`);
-			entries.splice(i, 1);
-			weeks.splice(i, 1);
+App.Reminders.addField = function() {
+
+	function addReminder() {
+		const week = Number(V.reminderWeek);
+
+		if (Number.isNaN(week)) {
+			return;
 		}
+
+		App.Reminders.add(V.reminderEntry, V.week + week);
+		V.reminderEntry = "";
+		V.reminderWeek = "";
 	}
-	V.reminders.text = text;
+
+	let r = "<<textbox '$reminderEntry' ''>> in <<textbox '$reminderWeek' ''>> weeks.";
+
+	return `<div>${r} ${App.UI.link("Add", addReminder, [], passage())}</div>`;
+};
+
+App.Reminders.fullDisplay = function() {
+	let r = "<h2>Reminders</h2>";
+
+	let list = App.Reminders.list();
+	if (list !== "") {
+		r += `<div class="indent">${list}</div>`;
+	}
+
+	return `${r}<h3>Add new</h3><div>${App.Reminders.addField()}</div>`;
 };
diff --git a/src/init/storyInit.tw b/src/init/storyInit.tw
index 313bf28586d..88fa2fcd158 100644
--- a/src/init/storyInit.tw
+++ b/src/init/storyInit.tw
@@ -472,7 +472,7 @@ You should have received a copy of the GNU General Public License along with thi
 <<set $REReductionCheckinIDs = []>>
 <<set $activeSlave = 0>>
 <<set $activeChild = 0>>
-<<set $reminders = {entries: [], weeks: [], text: [], overdue: []}>>
+<<set $reminders = []>>
 
 <<set $boomerangSlave = 0, $boomerangWeeks = 0, $boomerangBuyer = 0>>
 
diff --git a/src/pregmod/managePersonalAffairs.tw b/src/pregmod/managePersonalAffairs.tw
index 99f8f73029f..baf6df894b6 100644
--- a/src/pregmod/managePersonalAffairs.tw
+++ b/src/pregmod/managePersonalAffairs.tw
@@ -216,38 +216,9 @@ Sclera:
 	<</if>>
 <</if>>
 
-<br><br>
+<<= App.Reminders.fullDisplay()>>
 
-<<if $reminders.overdue.length > 1 || $reminders.text.length > 1>>
-	<i>Apologies, <<= properTitle()>>, but because of the way the reminder system is set up, each entry must be removed last-to-first to avoid causing errors.</i>
-	<br>
-<</if>>
-<<if $reminders.overdue.length > 1>>
-	<span class="yellow">	/* TODO: this would be a good place for an "attn" or "attention" class */
-		You have <<= numberWithPluralOne($reminders.overdue.length-1, "overdue reminder")>>:
-	</span>
-	<<print $reminders.overdue.join('<br>&nbsp;&nbsp;&nbsp;&nbsp;')>>
-	<br>
-<</if>>
-<<if $reminders.text.length > 1>>
-	You have <<=numberWithPluralOne($reminders.text.length-1, "upcoming reminder")>> set:
-	<<print $reminders.text.join('<br>&nbsp;&nbsp;&nbsp;&nbsp;')>>
-<<else>>
-	You do not have any upcoming reminders set.
-<</if>>
-<br>
-Remind me
-<<textbox "$reminderEntry" "">>
-in
-<<textbox "$reminderWeek" "">>
-weeks.
-[[Add|Manage Personal Affairs][App.Reminders.add($reminderEntry, $reminderWeek)]]
 <br>
-<<if $reminders.text.length > 0 || $reminders.overdue.length > 0 || $cheatMode || $debugMode>>
-	[[Clear your reminders|Manage Personal Affairs][$reminders = {entries: [], weeks: [], text: [], overdue: []}]]
-<</if>>
-
-<br><br>
 
 You ponder what skills may be useful in running your arcology.
 <br>Trading:
diff --git a/src/uncategorized/BackwardsCompatibility.tw b/src/uncategorized/BackwardsCompatibility.tw
index 9f2b91a99cf..d11934e0f25 100644
--- a/src/uncategorized/BackwardsCompatibility.tw
+++ b/src/uncategorized/BackwardsCompatibility.tw
@@ -153,8 +153,19 @@
 	<<set $weddingPlanned = 0>>
 <</if>>
 
-<<if ndef $reminders || ndef $reminders.overdue>>
-	<<set $reminders = {entries: [], weeks: [], text: [], overdue: []}>>
+<<if ndef $reminders>>
+	$reminders = [];
+<<elseif !Array.isArray($reminders)>>
+	<<set _r = $reminders, $reminders = []>>
+	<<for _i = 0; _i < _r.entries.length; _i++>>
+		<<run App.Reminders.add(_r.entries[_i], $week + Number(_r.weeks[_i]))>>
+	<</for>>
+	<<for _i = 0; _i < _r.overdue.length; _i++>>
+		<<set _s = _r.overdue[_i].split(" ")>>
+		<<run _s.splice(_s.length-5, 5)>>
+		<<set _s = _s.join(" ")>>
+		<<run App.Reminders.add(_s, $week - 1)>>
+	<</for>>
 <</if>>
 
 <<if $releaseID < 1057>>
diff --git a/src/uncategorized/endWeek.tw b/src/uncategorized/endWeek.tw
index 8d0b2937930..d2889dcd828 100644
--- a/src/uncategorized/endWeek.tw
+++ b/src/uncategorized/endWeek.tw
@@ -43,10 +43,6 @@
 	s.lastWeeksRepExpenses = 0;
 })>>
 
-<<if $reminders.text.length > 0>>
-	<<run App.Reminders.endweek()>>
-<</if>>
-
 <<if $organs.length > 0>>
 	<<run $organs.forEach(function(o) {
 		if (o.weeksToCompletion > 0) {
diff --git a/src/uncategorized/main.tw b/src/uncategorized/main.tw
index 1fe90408f86..38b44494c74 100644
--- a/src/uncategorized/main.tw
+++ b/src/uncategorized/main.tw
@@ -81,24 +81,8 @@
 	[[Hide|Main][$seeDesk = 0]]
 <</if>>
 
-<<if $reminders.overdue.length > 1 || $reminders.text.length > 1>>
-	<br>
-	<i>Apologies, <<= properTitle()>>, but because of the way the reminder system is set up, each entry must be removed last-to-first to avoid causing errors.</i>
-	<br>
-<</if>>
-<<if $reminders.overdue.length > 1>>
-	<span class="yellow">	/* TODO: this would be a good place for an "attn" or "attention" class */
-		You have <<= numberWithPluralOne($reminders.overdue.length-1, "overdue reminder")>>:
-	</span>
-	<<print $reminders.overdue.join('<br>&nbsp;&nbsp;&nbsp;&nbsp;')>>
-	<br>
-<</if>>
-<<if $reminders.text.length > 1>>
-	You have <<=numberWithPluralOne($reminders.text.length-1, "upcoming reminder")>>:
-	<<print $reminders.text.join('<br>&nbsp;&nbsp;&nbsp;&nbsp;')>>
-	<br>
-<</if>>
-<<if $reminders.text.length > 1 || $reminders.overdue.length > 1>>
+<<= App.Reminders.list({maxFuture: 5})>>
+<<if $reminders.length > 0>>
 	[[Manage reminders|Manage Personal Affairs]]
 <</if>>
 
-- 
GitLab