cardDate.js 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  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. return ReactiveCache.getCurrentUser().isShowWeekOfYear();
  116. },
  117. showDate() {
  118. return calendar(this.date.get());
  119. },
  120. showISODate() {
  121. return this.date.get().toISOString();
  122. },
  123. });
  124. class CardReceivedDate extends CardDate {
  125. onCreated() {
  126. super.onCreated();
  127. const self = this;
  128. self.autorun(() => {
  129. self.date.set(new Date(self.data().getReceived()));
  130. });
  131. }
  132. classes() {
  133. let classes = 'received-date ';
  134. const dueAt = this.data().getDue();
  135. const endAt = this.data().getEnd();
  136. const startAt = this.data().getStart();
  137. const theDate = this.date.get();
  138. // if dueAt, endAt and startAt exist & are > receivedAt, receivedAt doesn't need to be flagged
  139. if (
  140. (startAt && isAfter(theDate, startAt)) ||
  141. (endAt && isAfter(theDate, endAt)) ||
  142. (dueAt && isAfter(theDate, dueAt))
  143. )
  144. classes += 'long-overdue';
  145. else classes += 'current';
  146. return classes;
  147. }
  148. showTitle() {
  149. return `${TAPi18n.__('card-received-on')} ${format(this.date.get(), 'LLLL')}`;
  150. }
  151. events() {
  152. return super.events().concat({
  153. 'click .js-edit-date': Popup.open('editCardReceivedDate'),
  154. });
  155. }
  156. }
  157. CardReceivedDate.register('cardReceivedDate');
  158. class CardStartDate extends CardDate {
  159. onCreated() {
  160. super.onCreated();
  161. const self = this;
  162. self.autorun(() => {
  163. self.date.set(new Date(self.data().getStart()));
  164. });
  165. }
  166. classes() {
  167. let classes = 'start-date' + ' ';
  168. const dueAt = this.data().getDue();
  169. const endAt = this.data().getEnd();
  170. const theDate = this.date.get();
  171. const now = this.now.get();
  172. // if dueAt or endAt exist & are > startAt, startAt doesn't need to be flagged
  173. if ((endAt && isAfter(theDate, endAt)) || (dueAt && isAfter(theDate, dueAt)))
  174. classes += 'long-overdue';
  175. else if (isAfter(theDate, now)) classes += '';
  176. else classes += 'current';
  177. return classes;
  178. }
  179. showTitle() {
  180. return `${TAPi18n.__('card-start-on')} ${format(this.date.get(), 'LLLL')}`;
  181. }
  182. events() {
  183. return super.events().concat({
  184. 'click .js-edit-date': Popup.open('editCardStartDate'),
  185. });
  186. }
  187. }
  188. CardStartDate.register('cardStartDate');
  189. class CardDueDate extends CardDate {
  190. onCreated() {
  191. super.onCreated();
  192. const self = this;
  193. self.autorun(() => {
  194. self.date.set(new Date(self.data().getDue()));
  195. });
  196. }
  197. classes() {
  198. let classes = 'due-date' + ' ';
  199. const endAt = this.data().getEnd();
  200. const theDate = this.date.get();
  201. const now = this.now.get();
  202. // if the due date is after the end date, green - done early
  203. if (endAt && isAfter(theDate, endAt)) classes += 'current';
  204. // if there is an end date, don't need to flag the due date
  205. else if (endAt) classes += '';
  206. else if (diff(now, theDate, 'days') >= 2) classes += 'long-overdue';
  207. else if (diff(now, theDate, 'minute') >= 0) classes += 'due';
  208. else if (diff(now, theDate, 'days') >= -1) classes += 'almost-due';
  209. return classes;
  210. }
  211. showTitle() {
  212. return `${TAPi18n.__('card-due-on')} ${format(this.date.get(), 'LLLL')}`;
  213. }
  214. events() {
  215. return super.events().concat({
  216. 'click .js-edit-date': Popup.open('editCardDueDate'),
  217. });
  218. }
  219. }
  220. CardDueDate.register('cardDueDate');
  221. class CardEndDate extends CardDate {
  222. onCreated() {
  223. super.onCreated();
  224. const self = this;
  225. self.autorun(() => {
  226. self.date.set(new Date(self.data().getEnd()));
  227. });
  228. }
  229. classes() {
  230. let classes = 'end-date' + ' ';
  231. const dueAt = this.data().getDue();
  232. const theDate = this.date.get();
  233. if (!dueAt) classes += '';
  234. else if (isBefore(theDate, dueAt)) classes += 'current';
  235. else if (isAfter(theDate, dueAt)) classes += 'due';
  236. return classes;
  237. }
  238. showTitle() {
  239. return `${TAPi18n.__('card-end-on')} ${format(this.date.get(), 'LLLL')}`;
  240. }
  241. events() {
  242. return super.events().concat({
  243. 'click .js-edit-date': Popup.open('editCardEndDate'),
  244. });
  245. }
  246. }
  247. CardEndDate.register('cardEndDate');
  248. class CardCustomFieldDate extends CardDate {
  249. template() {
  250. return 'dateCustomField';
  251. }
  252. onCreated() {
  253. super.onCreated();
  254. const self = this;
  255. self.autorun(() => {
  256. self.date.set(new Date(self.data().value));
  257. });
  258. }
  259. showWeek() {
  260. return getISOWeek(this.date.get()).toString();
  261. }
  262. showWeekOfYear() {
  263. return ReactiveCache.getCurrentUser().isShowWeekOfYear();
  264. }
  265. showDate() {
  266. // this will start working once mquandalle:moment
  267. // is updated to at least moment.js 2.10.5
  268. // until then, the date is displayed in the "L" format
  269. return this.date.get().calendar(null, {
  270. sameElse: 'llll',
  271. });
  272. }
  273. showTitle() {
  274. return `${format(this.date.get(), 'LLLL')}`;
  275. }
  276. classes() {
  277. return 'customfield-date';
  278. }
  279. events() {
  280. return [];
  281. }
  282. }
  283. CardCustomFieldDate.register('cardCustomFieldDate');
  284. (class extends CardReceivedDate {
  285. template() {
  286. return 'minicardReceivedDate';
  287. }
  288. showDate() {
  289. return format(this.date.get(), 'L');
  290. }
  291. }.register('minicardReceivedDate'));
  292. (class extends CardStartDate {
  293. template() {
  294. return 'minicardStartDate';
  295. }
  296. showDate() {
  297. return format(this.date.get(), 'YYYY-MM-DD HH:mm');
  298. }
  299. }.register('minicardStartDate'));
  300. (class extends CardDueDate {
  301. template() {
  302. return 'minicardDueDate';
  303. }
  304. showDate() {
  305. return format(this.date.get(), 'YYYY-MM-DD HH:mm');
  306. }
  307. }.register('minicardDueDate'));
  308. (class extends CardEndDate {
  309. template() {
  310. return 'minicardEndDate';
  311. }
  312. showDate() {
  313. return format(this.date.get(), 'YYYY-MM-DD HH:mm');
  314. }
  315. }.register('minicardEndDate'));
  316. (class extends CardCustomFieldDate {
  317. template() {
  318. return 'minicardCustomFieldDate';
  319. }
  320. showDate() {
  321. return format(this.date.get(), 'L');
  322. }
  323. }.register('minicardCustomFieldDate'));
  324. class VoteEndDate extends CardDate {
  325. onCreated() {
  326. super.onCreated();
  327. const self = this;
  328. self.autorun(() => {
  329. self.date.set(new Date(self.data().getVoteEnd()));
  330. });
  331. }
  332. classes() {
  333. const classes = 'end-date' + ' ';
  334. return classes;
  335. }
  336. showDate() {
  337. return format(this.date.get(), 'L') + ' ' + format(this.date.get(), 'HH:mm');
  338. }
  339. showTitle() {
  340. return `${TAPi18n.__('card-end-on')} ${this.date.get().toLocaleString()}`;
  341. }
  342. events() {
  343. return super.events().concat({
  344. 'click .js-edit-date': Popup.open('editVoteEndDate'),
  345. });
  346. }
  347. }
  348. VoteEndDate.register('voteEndDate');
  349. class PokerEndDate extends CardDate {
  350. onCreated() {
  351. super.onCreated();
  352. const self = this;
  353. self.autorun(() => {
  354. self.date.set(new Date(self.data().getPokerEnd()));
  355. });
  356. }
  357. classes() {
  358. const classes = 'end-date' + ' ';
  359. return classes;
  360. }
  361. showDate() {
  362. return format(this.date.get(), 'l LT');
  363. }
  364. showTitle() {
  365. return `${TAPi18n.__('card-end-on')} ${format(this.date.get(), 'LLLL')}`;
  366. }
  367. events() {
  368. return super.events().concat({
  369. 'click .js-edit-date': Popup.open('editPokerEndDate'),
  370. });
  371. }
  372. }
  373. PokerEndDate.register('pokerEndDate');