cardDate.js 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. import { Utils } from '/client/lib/utils';
  2. import moment from 'moment/min/moment-with-locales';
  3. import { TAPi18n } from '/imports/i18n';
  4. import { DatePicker } from '/client/lib/datepicker';
  5. // Add this helper function at the top level
  6. const formatDate = (date, format) => {
  7. if (!date) return '';
  8. const normalizedDate = Utils.normalizeDigits(moment(date).format(format));
  9. return normalizedDate;
  10. };
  11. // editCardReceivedDatePopup
  12. (class extends DatePicker {
  13. onCreated() {
  14. super.onCreated(moment().format('YYYY-MM-DD HH:mm'));
  15. this.data().getReceived() &&
  16. this.date.set(moment(this.data().getReceived()));
  17. }
  18. _storeDate(date) {
  19. this.card.setReceived(moment(date).format('YYYY-MM-DD HH:mm'));
  20. }
  21. _deleteDate() {
  22. this.card.unsetReceived();
  23. }
  24. }.register('editCardReceivedDatePopup'));
  25. // editCardStartDatePopup
  26. (class extends DatePicker {
  27. onCreated() {
  28. super.onCreated(moment().format('YYYY-MM-DD HH:mm'));
  29. this.data().getStart() && this.date.set(moment(this.data().getStart()));
  30. }
  31. onRendered() {
  32. super.onRendered();
  33. if (moment.isDate(this.card.getReceived())) {
  34. this.$('.js-datepicker').datepicker(
  35. 'setStartDate',
  36. this.card.getReceived(),
  37. );
  38. }
  39. }
  40. _storeDate(date) {
  41. this.card.setStart(moment(date).format('YYYY-MM-DD HH:mm'));
  42. }
  43. _deleteDate() {
  44. this.card.unsetStart();
  45. }
  46. }.register('editCardStartDatePopup'));
  47. // editCardDueDatePopup
  48. (class extends DatePicker {
  49. onCreated() {
  50. super.onCreated('1970-01-01 17:00:00');
  51. this.data().getDue() && this.date.set(moment(this.data().getDue()));
  52. }
  53. onRendered() {
  54. super.onRendered();
  55. if (moment.isDate(this.card.getStart())) {
  56. this.$('.js-datepicker').datepicker('setStartDate', this.card.getStart());
  57. }
  58. }
  59. _storeDate(date) {
  60. this.card.setDue(moment(date).format('YYYY-MM-DD HH:mm'));
  61. }
  62. _deleteDate() {
  63. this.card.unsetDue();
  64. }
  65. }.register('editCardDueDatePopup'));
  66. // editCardEndDatePopup
  67. (class extends DatePicker {
  68. onCreated() {
  69. super.onCreated(moment().format('YYYY-MM-DD HH:mm'));
  70. this.data().getEnd() && this.date.set(moment(this.data().getEnd()));
  71. }
  72. onRendered() {
  73. super.onRendered();
  74. if (moment.isDate(this.card.getStart())) {
  75. this.$('.js-datepicker').datepicker('setStartDate', this.card.getStart());
  76. }
  77. }
  78. _storeDate(date) {
  79. this.card.setEnd(moment(date).format('YYYY-MM-DD HH:mm'));
  80. }
  81. _deleteDate() {
  82. this.card.unsetEnd();
  83. }
  84. }.register('editCardEndDatePopup'));
  85. // Display received, start, due & end dates
  86. const CardDate = BlazeComponent.extendComponent({
  87. template() {
  88. return 'dateBadge';
  89. },
  90. onCreated() {
  91. const self = this;
  92. self.date = ReactiveVar();
  93. self.now = ReactiveVar(moment());
  94. window.setInterval(() => {
  95. self.now.set(moment());
  96. }, 60000);
  97. },
  98. showWeek() {
  99. return this.date.get().week().toString();
  100. },
  101. showWeekOfYear() {
  102. return ReactiveCache.getCurrentUser().isShowWeekOfYear();
  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. showDate() {
  151. return formatDate(this.date.get(), 'L');
  152. }
  153. }
  154. CardReceivedDate.register('cardReceivedDate');
  155. class CardStartDate extends CardDate {
  156. onCreated() {
  157. super.onCreated();
  158. const self = this;
  159. self.autorun(() => {
  160. self.date.set(moment(self.data().getStart()));
  161. });
  162. }
  163. classes() {
  164. let classes = 'start-date' + ' ';
  165. const dueAt = this.data().getDue();
  166. const endAt = this.data().getEnd();
  167. const theDate = this.date.get();
  168. const now = this.now.get();
  169. // if dueAt or endAt exist & are > startAt, startAt doesn't need to be flagged
  170. if ((endAt && theDate.isAfter(endAt)) || (dueAt && theDate.isAfter(dueAt)))
  171. classes += 'long-overdue';
  172. else if (theDate.isAfter(now)) classes += '';
  173. else classes += 'current';
  174. return classes;
  175. }
  176. showTitle() {
  177. return `${TAPi18n.__('card-start-on')} ${this.date.get().format('LLLL')}`;
  178. }
  179. events() {
  180. return super.events().concat({
  181. 'click .js-edit-date': Popup.open('editCardStartDate'),
  182. });
  183. }
  184. showDate() {
  185. return formatDate(this.date.get(), 'L');
  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(moment(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 && theDate.isAfter(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 (now.diff(theDate, 'days') >= 2) classes += 'long-overdue';
  207. else if (now.diff(theDate, 'minute') >= 0) classes += 'due';
  208. else if (now.diff(theDate, 'days') >= -1) classes += 'almost-due';
  209. return classes;
  210. }
  211. showTitle() {
  212. return `${TAPi18n.__('card-due-on')} ${this.date.get().format('LLLL')}`;
  213. }
  214. events() {
  215. return super.events().concat({
  216. 'click .js-edit-date': Popup.open('editCardDueDate'),
  217. });
  218. }
  219. showDate() {
  220. return formatDate(this.date.get(), 'L');
  221. }
  222. }
  223. CardDueDate.register('cardDueDate');
  224. class CardEndDate extends CardDate {
  225. onCreated() {
  226. super.onCreated();
  227. const self = this;
  228. self.autorun(() => {
  229. self.date.set(moment(self.data().getEnd()));
  230. });
  231. }
  232. classes() {
  233. let classes = 'end-date' + ' ';
  234. const dueAt = this.data().getDue();
  235. const theDate = this.date.get();
  236. if (!dueAt) classes += '';
  237. else if (theDate.isBefore(dueAt)) classes += 'current';
  238. else if (theDate.isAfter(dueAt)) classes += 'due';
  239. return classes;
  240. }
  241. showTitle() {
  242. return `${TAPi18n.__('card-end-on')} ${this.date.get().format('LLLL')}`;
  243. }
  244. events() {
  245. return super.events().concat({
  246. 'click .js-edit-date': Popup.open('editCardEndDate'),
  247. });
  248. }
  249. showDate() {
  250. return formatDate(this.date.get(), 'L');
  251. }
  252. }
  253. CardEndDate.register('cardEndDate');
  254. class CardCustomFieldDate extends CardDate {
  255. template() {
  256. return 'dateCustomField';
  257. }
  258. onCreated() {
  259. super.onCreated();
  260. const self = this;
  261. self.autorun(() => {
  262. self.date.set(moment(self.data().value));
  263. });
  264. }
  265. showWeek() {
  266. return this.date.get().week().toString();
  267. }
  268. showWeekOfYear() {
  269. return ReactiveCache.getCurrentUser().isShowWeekOfYear();
  270. }
  271. showDate() {
  272. // this will start working once mquandalle:moment
  273. // is updated to at least moment.js 2.10.5
  274. // until then, the date is displayed in the "L" format
  275. return this.date.get().calendar(null, {
  276. sameElse: 'llll',
  277. });
  278. }
  279. showTitle() {
  280. return `${this.date.get().format('LLLL')}`;
  281. }
  282. classes() {
  283. return 'customfield-date';
  284. }
  285. events() {
  286. return [];
  287. }
  288. }
  289. CardCustomFieldDate.register('cardCustomFieldDate');
  290. (class extends CardReceivedDate {
  291. showDate() {
  292. return formatDate(this.date.get(), 'L');
  293. }
  294. }.register('minicardReceivedDate'));
  295. (class extends CardStartDate {
  296. showDate() {
  297. return formatDate(this.date.get(), 'YYYY-MM-DD HH:mm');
  298. }
  299. }.register('minicardStartDate'));
  300. (class extends CardDueDate {
  301. showDate() {
  302. return formatDate(this.date.get(), 'YYYY-MM-DD HH:mm');
  303. }
  304. }.register('minicardDueDate'));
  305. (class extends CardEndDate {
  306. showDate() {
  307. return formatDate(this.date.get(), 'YYYY-MM-DD HH:mm');
  308. }
  309. }.register('minicardEndDate'));
  310. (class extends CardCustomFieldDate {
  311. showDate() {
  312. return formatDate(this.date.get(), 'L');
  313. }
  314. }.register('minicardCustomFieldDate'));
  315. class VoteEndDate extends CardDate {
  316. onCreated() {
  317. super.onCreated();
  318. const self = this;
  319. self.autorun(() => {
  320. self.date.set(moment(self.data().getVoteEnd()));
  321. });
  322. }
  323. classes() {
  324. const classes = 'end-date' + ' ';
  325. return classes;
  326. }
  327. showDate() {
  328. return formatDate(this.date.get(), 'L LT');
  329. }
  330. showTitle() {
  331. return `${TAPi18n.__('card-end-on')} ${this.date.get().format('LLLL')}`;
  332. }
  333. events() {
  334. return super.events().concat({
  335. 'click .js-edit-date': Popup.open('editVoteEndDate'),
  336. });
  337. }
  338. }
  339. VoteEndDate.register('voteEndDate');
  340. class PokerEndDate extends CardDate {
  341. onCreated() {
  342. super.onCreated();
  343. const self = this;
  344. self.autorun(() => {
  345. self.date.set(moment(self.data().getPokerEnd()));
  346. });
  347. }
  348. classes() {
  349. const classes = 'end-date' + ' ';
  350. return classes;
  351. }
  352. showDate() {
  353. return formatDate(this.date.get(), 'L LT');
  354. }
  355. showTitle() {
  356. return `${TAPi18n.__('card-end-on')} ${this.date.get().format('LLLL')}`;
  357. }
  358. events() {
  359. return super.events().concat({
  360. 'click .js-edit-date': Popup.open('editPokerEndDate'),
  361. });
  362. }
  363. }
  364. PokerEndDate.register('pokerEndDate');