cardDate.js 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. import { TAPi18n } from '/imports/i18n';
  2. import { DatePicker } from '/client/lib/datepicker';
  3. import {
  4. formatDateTime,
  5. formatDate,
  6. formatTime,
  7. getISOWeek,
  8. isValidDate,
  9. isBefore,
  10. isAfter,
  11. isSame,
  12. add,
  13. subtract,
  14. startOf,
  15. endOf,
  16. format,
  17. parseDate,
  18. now,
  19. createDate,
  20. fromNow,
  21. calendar,
  22. diff
  23. } from '/imports/lib/dateUtils';
  24. // editCardReceivedDatePopup
  25. (class extends DatePicker {
  26. onCreated() {
  27. super.onCreated(formatDateTime(now()));
  28. this.data().getReceived() &&
  29. this.date.set(new Date(this.data().getReceived()));
  30. }
  31. _storeDate(date) {
  32. this.card.setReceived(formatDateTime(date));
  33. }
  34. _deleteDate() {
  35. this.card.unsetReceived();
  36. }
  37. }.register('editCardReceivedDatePopup'));
  38. // editCardStartDatePopup
  39. (class extends DatePicker {
  40. onCreated() {
  41. super.onCreated(formatDateTime(now()));
  42. this.data().getStart() && this.date.set(new Date(this.data().getStart()));
  43. }
  44. onRendered() {
  45. super.onRendered();
  46. if (moment.isDate(this.card.getReceived())) {
  47. this.$('.js-datepicker').datepicker(
  48. 'setStartDate',
  49. this.card.getReceived(),
  50. );
  51. }
  52. }
  53. _storeDate(date) {
  54. this.card.setStart(formatDateTime(date));
  55. }
  56. _deleteDate() {
  57. this.card.unsetStart();
  58. }
  59. }.register('editCardStartDatePopup'));
  60. // editCardDueDatePopup
  61. (class extends DatePicker {
  62. onCreated() {
  63. super.onCreated('1970-01-01 17:00:00');
  64. this.data().getDue() && this.date.set(new Date(this.data().getDue()));
  65. }
  66. onRendered() {
  67. super.onRendered();
  68. if (moment.isDate(this.card.getStart())) {
  69. this.$('.js-datepicker').datepicker('setStartDate', this.card.getStart());
  70. }
  71. }
  72. _storeDate(date) {
  73. this.card.setDue(formatDateTime(date));
  74. }
  75. _deleteDate() {
  76. this.card.unsetDue();
  77. }
  78. }.register('editCardDueDatePopup'));
  79. // editCardEndDatePopup
  80. (class extends DatePicker {
  81. onCreated() {
  82. super.onCreated(formatDateTime(now()));
  83. this.data().getEnd() && this.date.set(new Date(this.data().getEnd()));
  84. }
  85. onRendered() {
  86. super.onRendered();
  87. if (moment.isDate(this.card.getStart())) {
  88. this.$('.js-datepicker').datepicker('setStartDate', this.card.getStart());
  89. }
  90. }
  91. _storeDate(date) {
  92. this.card.setEnd(formatDateTime(date));
  93. }
  94. _deleteDate() {
  95. this.card.unsetEnd();
  96. }
  97. }.register('editCardEndDatePopup'));
  98. // Display received, start, due & end dates
  99. const CardDate = BlazeComponent.extendComponent({
  100. template() {
  101. return 'dateBadge';
  102. },
  103. onCreated() {
  104. const self = this;
  105. self.date = ReactiveVar();
  106. self.now = ReactiveVar(now());
  107. window.setInterval(() => {
  108. self.now.set(now());
  109. }, 60000);
  110. },
  111. showWeek() {
  112. return getISOWeek(this.date.get()).toString();
  113. },
  114. showWeekOfYear() {
  115. const user = ReactiveCache.getCurrentUser();
  116. if (!user) {
  117. // For non-logged-in users, week of year is not shown
  118. return false;
  119. }
  120. return user.isShowWeekOfYear();
  121. },
  122. showDate() {
  123. return calendar(this.date.get());
  124. },
  125. showISODate() {
  126. return this.date.get().toISOString();
  127. },
  128. });
  129. class CardReceivedDate extends CardDate {
  130. onCreated() {
  131. super.onCreated();
  132. const self = this;
  133. self.autorun(() => {
  134. self.date.set(new Date(self.data().getReceived()));
  135. });
  136. }
  137. classes() {
  138. let classes = 'received-date ';
  139. const dueAt = this.data().getDue();
  140. const endAt = this.data().getEnd();
  141. const startAt = this.data().getStart();
  142. const theDate = this.date.get();
  143. // if dueAt, endAt and startAt exist & are > receivedAt, receivedAt doesn't need to be flagged
  144. if (
  145. (startAt && isAfter(theDate, startAt)) ||
  146. (endAt && isAfter(theDate, endAt)) ||
  147. (dueAt && isAfter(theDate, dueAt))
  148. )
  149. classes += 'long-overdue';
  150. else classes += 'current';
  151. return classes;
  152. }
  153. showTitle() {
  154. return `${TAPi18n.__('card-received-on')} ${format(this.date.get(), 'LLLL')}`;
  155. }
  156. events() {
  157. return super.events().concat({
  158. 'click .js-edit-date': Popup.open('editCardReceivedDate'),
  159. });
  160. }
  161. }
  162. CardReceivedDate.register('cardReceivedDate');
  163. class CardStartDate extends CardDate {
  164. onCreated() {
  165. super.onCreated();
  166. const self = this;
  167. self.autorun(() => {
  168. self.date.set(new Date(self.data().getStart()));
  169. });
  170. }
  171. classes() {
  172. let classes = 'start-date' + ' ';
  173. const dueAt = this.data().getDue();
  174. const endAt = this.data().getEnd();
  175. const theDate = this.date.get();
  176. const now = this.now.get();
  177. // if dueAt or endAt exist & are > startAt, startAt doesn't need to be flagged
  178. if ((endAt && isAfter(theDate, endAt)) || (dueAt && isAfter(theDate, dueAt)))
  179. classes += 'long-overdue';
  180. else if (isAfter(theDate, now)) classes += '';
  181. else classes += 'current';
  182. return classes;
  183. }
  184. showTitle() {
  185. return `${TAPi18n.__('card-start-on')} ${format(this.date.get(), 'LLLL')}`;
  186. }
  187. events() {
  188. return super.events().concat({
  189. 'click .js-edit-date': Popup.open('editCardStartDate'),
  190. });
  191. }
  192. }
  193. CardStartDate.register('cardStartDate');
  194. class CardDueDate extends CardDate {
  195. onCreated() {
  196. super.onCreated();
  197. const self = this;
  198. self.autorun(() => {
  199. self.date.set(new Date(self.data().getDue()));
  200. });
  201. }
  202. classes() {
  203. let classes = 'due-date' + ' ';
  204. const endAt = this.data().getEnd();
  205. const theDate = this.date.get();
  206. const now = this.now.get();
  207. // if the due date is after the end date, green - done early
  208. if (endAt && isAfter(theDate, endAt)) classes += 'current';
  209. // if there is an end date, don't need to flag the due date
  210. else if (endAt) classes += '';
  211. else if (diff(now, theDate, 'days') >= 2) classes += 'long-overdue';
  212. else if (diff(now, theDate, 'minute') >= 0) classes += 'due';
  213. else if (diff(now, theDate, 'days') >= -1) classes += 'almost-due';
  214. return classes;
  215. }
  216. showTitle() {
  217. return `${TAPi18n.__('card-due-on')} ${format(this.date.get(), 'LLLL')}`;
  218. }
  219. events() {
  220. return super.events().concat({
  221. 'click .js-edit-date': Popup.open('editCardDueDate'),
  222. });
  223. }
  224. }
  225. CardDueDate.register('cardDueDate');
  226. class CardEndDate extends CardDate {
  227. onCreated() {
  228. super.onCreated();
  229. const self = this;
  230. self.autorun(() => {
  231. self.date.set(new Date(self.data().getEnd()));
  232. });
  233. }
  234. classes() {
  235. let classes = 'end-date' + ' ';
  236. const dueAt = this.data().getDue();
  237. const theDate = this.date.get();
  238. if (!dueAt) classes += '';
  239. else if (isBefore(theDate, dueAt)) classes += 'current';
  240. else if (isAfter(theDate, dueAt)) classes += 'due';
  241. return classes;
  242. }
  243. showTitle() {
  244. return `${TAPi18n.__('card-end-on')} ${format(this.date.get(), 'LLLL')}`;
  245. }
  246. events() {
  247. return super.events().concat({
  248. 'click .js-edit-date': Popup.open('editCardEndDate'),
  249. });
  250. }
  251. }
  252. CardEndDate.register('cardEndDate');
  253. class CardCustomFieldDate extends CardDate {
  254. template() {
  255. return 'dateCustomField';
  256. }
  257. onCreated() {
  258. super.onCreated();
  259. const self = this;
  260. self.autorun(() => {
  261. self.date.set(new Date(self.data().value));
  262. });
  263. }
  264. showWeek() {
  265. return getISOWeek(this.date.get()).toString();
  266. }
  267. showWeekOfYear() {
  268. const user = ReactiveCache.getCurrentUser();
  269. if (!user) {
  270. // For non-logged-in users, week of year is not shown
  271. return false;
  272. }
  273. return user.isShowWeekOfYear();
  274. }
  275. showDate() {
  276. // this will start working once mquandalle:moment
  277. // is updated to at least moment.js 2.10.5
  278. // until then, the date is displayed in the "L" format
  279. return this.date.get().calendar(null, {
  280. sameElse: 'llll',
  281. });
  282. }
  283. showTitle() {
  284. return `${format(this.date.get(), 'LLLL')}`;
  285. }
  286. classes() {
  287. return 'customfield-date';
  288. }
  289. events() {
  290. return [];
  291. }
  292. }
  293. CardCustomFieldDate.register('cardCustomFieldDate');
  294. (class extends CardReceivedDate {
  295. template() {
  296. return 'minicardReceivedDate';
  297. }
  298. showDate() {
  299. return format(this.date.get(), 'L');
  300. }
  301. }.register('minicardReceivedDate'));
  302. (class extends CardStartDate {
  303. template() {
  304. return 'minicardStartDate';
  305. }
  306. showDate() {
  307. return format(this.date.get(), 'YYYY-MM-DD HH:mm');
  308. }
  309. }.register('minicardStartDate'));
  310. (class extends CardDueDate {
  311. template() {
  312. return 'minicardDueDate';
  313. }
  314. showDate() {
  315. return format(this.date.get(), 'YYYY-MM-DD HH:mm');
  316. }
  317. }.register('minicardDueDate'));
  318. (class extends CardEndDate {
  319. template() {
  320. return 'minicardEndDate';
  321. }
  322. showDate() {
  323. return format(this.date.get(), 'YYYY-MM-DD HH:mm');
  324. }
  325. }.register('minicardEndDate'));
  326. (class extends CardCustomFieldDate {
  327. template() {
  328. return 'minicardCustomFieldDate';
  329. }
  330. showDate() {
  331. return format(this.date.get(), 'L');
  332. }
  333. }.register('minicardCustomFieldDate'));
  334. class VoteEndDate extends CardDate {
  335. onCreated() {
  336. super.onCreated();
  337. const self = this;
  338. self.autorun(() => {
  339. self.date.set(new Date(self.data().getVoteEnd()));
  340. });
  341. }
  342. classes() {
  343. const classes = 'end-date' + ' ';
  344. return classes;
  345. }
  346. showDate() {
  347. return format(this.date.get(), 'L') + ' ' + format(this.date.get(), 'HH:mm');
  348. }
  349. showTitle() {
  350. return `${TAPi18n.__('card-end-on')} ${this.date.get().toLocaleString()}`;
  351. }
  352. events() {
  353. return super.events().concat({
  354. 'click .js-edit-date': Popup.open('editVoteEndDate'),
  355. });
  356. }
  357. }
  358. VoteEndDate.register('voteEndDate');
  359. class PokerEndDate extends CardDate {
  360. onCreated() {
  361. super.onCreated();
  362. const self = this;
  363. self.autorun(() => {
  364. self.date.set(new Date(self.data().getPokerEnd()));
  365. });
  366. }
  367. classes() {
  368. const classes = 'end-date' + ' ';
  369. return classes;
  370. }
  371. showDate() {
  372. return format(this.date.get(), 'l LT');
  373. }
  374. showTitle() {
  375. return `${TAPi18n.__('card-end-on')} ${format(this.date.get(), 'LLLL')}`;
  376. }
  377. events() {
  378. return super.events().concat({
  379. 'click .js-edit-date': Popup.open('editPokerEndDate'),
  380. });
  381. }
  382. }
  383. PokerEndDate.register('pokerEndDate');