cardDate.js 9.6 KB

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