cardDate.js 9.2 KB

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