dueCards.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. import { ReactiveCache } from '/imports/reactiveCache';
  2. import { CardSearchPagedComponent } from '../../lib/cardSearch';
  3. import {
  4. OPERATOR_HAS,
  5. OPERATOR_SORT,
  6. OPERATOR_USER,
  7. ORDER_ASCENDING,
  8. PREDICATE_DUE_AT,
  9. } from '../../../config/search-const';
  10. import { QueryParams } from '../../../config/query-classes';
  11. // const subManager = new SubsManager();
  12. BlazeComponent.extendComponent({
  13. dueCardsView() {
  14. // eslint-disable-next-line no-console
  15. // console.log('sort:', Utils.dueCardsView());
  16. return Utils && Utils.dueCardsView ? Utils.dueCardsView() : 'me';
  17. },
  18. events() {
  19. return [
  20. {
  21. 'click .js-due-cards-view-change': Popup.open('dueCardsViewChange'),
  22. },
  23. ];
  24. },
  25. }).register('dueCardsHeaderBar');
  26. Template.dueCards.helpers({
  27. userId() {
  28. return Meteor.userId();
  29. },
  30. dueCardsList() {
  31. const component = BlazeComponent.getComponentForElement(this);
  32. if (component && component.dueCardsList) {
  33. return component.dueCardsList();
  34. }
  35. return [];
  36. },
  37. });
  38. BlazeComponent.extendComponent({
  39. events() {
  40. return [
  41. {
  42. 'click .js-due-cards-view-me'() {
  43. if (Utils && Utils.setDueCardsView) {
  44. Utils.setDueCardsView('me');
  45. }
  46. Popup.back();
  47. },
  48. 'click .js-due-cards-view-all'() {
  49. if (Utils && Utils.setDueCardsView) {
  50. Utils.setDueCardsView('all');
  51. }
  52. Popup.back();
  53. },
  54. },
  55. ];
  56. },
  57. }).register('dueCardsViewChangePopup');
  58. class DueCardsComponent extends CardSearchPagedComponent {
  59. onCreated() {
  60. super.onCreated();
  61. // Add a small delay to ensure ReactiveCache is ready
  62. this.searchRetryCount = 0;
  63. this.maxRetries = 3;
  64. // Use a timeout to ensure the search runs after the component is fully initialized
  65. Meteor.setTimeout(() => {
  66. this.performSearch();
  67. }, 100);
  68. }
  69. performSearch() {
  70. if (process.env.DEBUG === 'true') {
  71. console.log('Performing due cards search, attempt:', this.searchRetryCount + 1);
  72. }
  73. // Check if user is authenticated
  74. const currentUser = ReactiveCache.getCurrentUser();
  75. if (!currentUser) {
  76. if (process.env.DEBUG === 'true') {
  77. console.log('User not authenticated, waiting...');
  78. }
  79. Meteor.setTimeout(() => {
  80. this.performSearch();
  81. }, 1000);
  82. return;
  83. }
  84. if (process.env.DEBUG === 'true') {
  85. console.log('User authenticated:', currentUser.username);
  86. }
  87. const queryParams = new QueryParams();
  88. queryParams.addPredicate(OPERATOR_HAS, {
  89. field: PREDICATE_DUE_AT,
  90. exists: true,
  91. });
  92. // queryParams[OPERATOR_LIMIT] = 5;
  93. queryParams.addPredicate(OPERATOR_SORT, {
  94. name: PREDICATE_DUE_AT,
  95. order: ORDER_ASCENDING,
  96. });
  97. // Note: User filtering is handled server-side based on board membership
  98. // The OPERATOR_USER filter is too restrictive as it only shows cards where
  99. // the user is assigned or a member of the card, not the board
  100. // if (Utils && Utils.dueCardsView && Utils.dueCardsView() !== 'all') {
  101. // const currentUser = ReactiveCache.getCurrentUser();
  102. // if (currentUser && currentUser.username) {
  103. // queryParams.addPredicate(OPERATOR_USER, currentUser.username);
  104. // }
  105. // }
  106. // Debug: Log the query parameters
  107. if (process.env.DEBUG === 'true') {
  108. console.log('Due cards query params:', queryParams.params);
  109. console.log('Due cards query text:', queryParams.text);
  110. console.log('Due cards has predicates:', queryParams.getPredicates('has'));
  111. console.log('Due cards sort predicates:', queryParams.getPredicates('sort'));
  112. }
  113. this.runGlobalSearch(queryParams);
  114. }
  115. dueCardsView() {
  116. // eslint-disable-next-line no-console
  117. //console.log('sort:', Utils.dueCardsView());
  118. return Utils && Utils.dueCardsView ? Utils.dueCardsView() : 'me';
  119. }
  120. sortByBoard() {
  121. return this.dueCardsView() === 'board';
  122. }
  123. dueCardsList() {
  124. const results = this.getResults();
  125. console.log('results:', results);
  126. const cards = [];
  127. if (results) {
  128. results.forEach(card => {
  129. cards.push(card);
  130. });
  131. }
  132. // Sort by due date: oldest first (ascending order)
  133. cards.sort((a, b) => {
  134. // Handle null/undefined due dates by putting them at the end
  135. const aDueAt = a.dueAt ? new Date(a.dueAt) : new Date('2100-12-31');
  136. const bDueAt = b.dueAt ? new Date(b.dueAt) : new Date('2100-12-31');
  137. // Debug logging
  138. if (process.env.DEBUG === 'true') {
  139. console.log(`Comparing cards: "${a.title}" (${a.dueAt}) vs "${b.title}" (${b.dueAt})`);
  140. console.log(`Parsed dates: ${aDueAt.toISOString()} vs ${bDueAt.toISOString()}`);
  141. console.log(`Time difference: ${aDueAt.getTime() - bDueAt.getTime()}`);
  142. }
  143. // Compare dates: if a is earlier than b, return negative (a comes first)
  144. // if a is later than b, return positive (b comes first)
  145. return aDueAt.getTime() - bDueAt.getTime();
  146. });
  147. // eslint-disable-next-line no-console
  148. console.log('cards sorted by due date (oldest first):', cards);
  149. return cards;
  150. }
  151. }
  152. DueCardsComponent.register('dueCards');