|
@@ -1,13 +1,5 @@
|
|
|
import { ReactiveCache } from '/imports/reactiveCache';
|
|
|
-import { CardSearchPagedComponent } from '../../lib/cardSearch';
|
|
|
-import {
|
|
|
- OPERATOR_HAS,
|
|
|
- OPERATOR_SORT,
|
|
|
- OPERATOR_USER,
|
|
|
- ORDER_ASCENDING,
|
|
|
- PREDICATE_DUE_AT,
|
|
|
-} from '../../../config/search-const';
|
|
|
-import { QueryParams } from '../../../config/query-classes';
|
|
|
+import { BlazeComponent } from 'meteor/peerlibrary:blaze-components';
|
|
|
|
|
|
// const subManager = new SubsManager();
|
|
|
|
|
@@ -38,6 +30,23 @@ Template.dueCards.helpers({
|
|
|
}
|
|
|
return [];
|
|
|
},
|
|
|
+ hasResults() {
|
|
|
+ const component = BlazeComponent.getComponentForElement(this);
|
|
|
+ if (component && component.dueCardsList) {
|
|
|
+ const cards = component.dueCardsList();
|
|
|
+ return cards && cards.length > 0;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ },
|
|
|
+ searching() {
|
|
|
+ return false; // No longer using search, so always false
|
|
|
+ },
|
|
|
+ hasQueryErrors() {
|
|
|
+ return false; // No longer using search, so always false
|
|
|
+ },
|
|
|
+ errorMessages() {
|
|
|
+ return []; // No longer using search, so always empty
|
|
|
+ },
|
|
|
});
|
|
|
|
|
|
BlazeComponent.extendComponent({
|
|
@@ -62,71 +71,29 @@ BlazeComponent.extendComponent({
|
|
|
},
|
|
|
}).register('dueCardsViewChangePopup');
|
|
|
|
|
|
-class DueCardsComponent extends CardSearchPagedComponent {
|
|
|
+class DueCardsComponent extends BlazeComponent {
|
|
|
onCreated() {
|
|
|
super.onCreated();
|
|
|
|
|
|
- // Add a small delay to ensure ReactiveCache is ready
|
|
|
- this.searchRetryCount = 0;
|
|
|
- this.maxRetries = 3;
|
|
|
+ this._cachedCards = null;
|
|
|
+ this._cachedTimestamp = null;
|
|
|
+ this.subscriptionHandle = null;
|
|
|
|
|
|
- // Use a timeout to ensure the search runs after the component is fully initialized
|
|
|
- Meteor.setTimeout(() => {
|
|
|
- this.performSearch();
|
|
|
- }, 100);
|
|
|
- }
|
|
|
-
|
|
|
- performSearch() {
|
|
|
- if (process.env.DEBUG === 'true') {
|
|
|
- console.log('Performing due cards search, attempt:', this.searchRetryCount + 1);
|
|
|
- }
|
|
|
-
|
|
|
- // Check if user is authenticated
|
|
|
- const currentUser = ReactiveCache.getCurrentUser();
|
|
|
- if (!currentUser) {
|
|
|
- if (process.env.DEBUG === 'true') {
|
|
|
- console.log('User not authenticated, waiting...');
|
|
|
+ // Subscribe to the optimized due cards publication
|
|
|
+ this.autorun(() => {
|
|
|
+ const allUsers = this.dueCardsView() === 'all';
|
|
|
+ if (this.subscriptionHandle) {
|
|
|
+ this.subscriptionHandle.stop();
|
|
|
}
|
|
|
- Meteor.setTimeout(() => {
|
|
|
- this.performSearch();
|
|
|
- }, 1000);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (process.env.DEBUG === 'true') {
|
|
|
- console.log('User authenticated:', currentUser.username);
|
|
|
- }
|
|
|
-
|
|
|
- const queryParams = new QueryParams();
|
|
|
- queryParams.addPredicate(OPERATOR_HAS, {
|
|
|
- field: PREDICATE_DUE_AT,
|
|
|
- exists: true,
|
|
|
- });
|
|
|
- // queryParams[OPERATOR_LIMIT] = 5;
|
|
|
- queryParams.addPredicate(OPERATOR_SORT, {
|
|
|
- name: PREDICATE_DUE_AT,
|
|
|
- order: ORDER_ASCENDING,
|
|
|
+ this.subscriptionHandle = Meteor.subscribe('dueCards', allUsers);
|
|
|
});
|
|
|
+ }
|
|
|
|
|
|
- // Note: User filtering is handled server-side based on board membership
|
|
|
- // The OPERATOR_USER filter is too restrictive as it only shows cards where
|
|
|
- // the user is assigned or a member of the card, not the board
|
|
|
- // if (Utils && Utils.dueCardsView && Utils.dueCardsView() !== 'all') {
|
|
|
- // const currentUser = ReactiveCache.getCurrentUser();
|
|
|
- // if (currentUser && currentUser.username) {
|
|
|
- // queryParams.addPredicate(OPERATOR_USER, currentUser.username);
|
|
|
- // }
|
|
|
- // }
|
|
|
-
|
|
|
- // Debug: Log the query parameters
|
|
|
- if (process.env.DEBUG === 'true') {
|
|
|
- console.log('Due cards query params:', queryParams.params);
|
|
|
- console.log('Due cards query text:', queryParams.text);
|
|
|
- console.log('Due cards has predicates:', queryParams.getPredicates('has'));
|
|
|
- console.log('Due cards sort predicates:', queryParams.getPredicates('sort'));
|
|
|
+ onDestroyed() {
|
|
|
+ super.onDestroyed();
|
|
|
+ if (this.subscriptionHandle) {
|
|
|
+ this.subscriptionHandle.stop();
|
|
|
}
|
|
|
-
|
|
|
- this.runGlobalSearch(queryParams);
|
|
|
}
|
|
|
|
|
|
dueCardsView() {
|
|
@@ -140,36 +107,36 @@ class DueCardsComponent extends CardSearchPagedComponent {
|
|
|
}
|
|
|
|
|
|
dueCardsList() {
|
|
|
- const results = this.getResults();
|
|
|
- console.log('results:', results);
|
|
|
- const cards = [];
|
|
|
- if (results) {
|
|
|
- results.forEach(card => {
|
|
|
- cards.push(card);
|
|
|
- });
|
|
|
+ // Use cached results if available to avoid expensive re-sorting
|
|
|
+ if (this._cachedCards && this._cachedTimestamp && (Date.now() - this._cachedTimestamp < 5000)) {
|
|
|
+ return this._cachedCards;
|
|
|
}
|
|
|
|
|
|
- // Sort by due date: oldest first (ascending order)
|
|
|
- cards.sort((a, b) => {
|
|
|
- // Handle null/undefined due dates by putting them at the end
|
|
|
- const aDueAt = a.dueAt ? new Date(a.dueAt) : new Date('2100-12-31');
|
|
|
- const bDueAt = b.dueAt ? new Date(b.dueAt) : new Date('2100-12-31');
|
|
|
-
|
|
|
- // Debug logging
|
|
|
- if (process.env.DEBUG === 'true') {
|
|
|
- console.log(`Comparing cards: "${a.title}" (${a.dueAt}) vs "${b.title}" (${b.dueAt})`);
|
|
|
- console.log(`Parsed dates: ${aDueAt.toISOString()} vs ${bDueAt.toISOString()}`);
|
|
|
- console.log(`Time difference: ${aDueAt.getTime() - bDueAt.getTime()}`);
|
|
|
- }
|
|
|
-
|
|
|
- // Compare dates: if a is earlier than b, return negative (a comes first)
|
|
|
- // if a is later than b, return positive (b comes first)
|
|
|
- return aDueAt.getTime() - bDueAt.getTime();
|
|
|
+ // Get cards directly from the subscription (already sorted by the publication)
|
|
|
+ const cards = ReactiveCache.getCards({
|
|
|
+ type: 'cardType-card',
|
|
|
+ archived: false,
|
|
|
+ dueAt: { $exists: true, $nin: [null, ''] }
|
|
|
});
|
|
|
|
|
|
- // eslint-disable-next-line no-console
|
|
|
- console.log('cards sorted by due date (oldest first):', cards);
|
|
|
- return cards;
|
|
|
+ // Filter cards based on user view preference
|
|
|
+ const allUsers = this.dueCardsView() === 'all';
|
|
|
+ const currentUser = ReactiveCache.getCurrentUser();
|
|
|
+ let filteredCards = cards;
|
|
|
+
|
|
|
+ if (!allUsers && currentUser) {
|
|
|
+ filteredCards = cards.filter(card => {
|
|
|
+ return card.members && card.members.includes(currentUser._id) ||
|
|
|
+ card.assignees && card.assignees.includes(currentUser._id) ||
|
|
|
+ card.userId === currentUser._id;
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ // Cache the results for 5 seconds to avoid re-filtering on every render
|
|
|
+ this._cachedCards = filteredCards;
|
|
|
+ this._cachedTimestamp = Date.now();
|
|
|
+
|
|
|
+ return filteredCards;
|
|
|
}
|
|
|
}
|
|
|
|