85 lines
3.1 KiB
JavaScript
85 lines
3.1 KiB
JavaScript
function createConversationPager({ loadPage }) {
|
|
let state = { comments: [], page: 1, older_page: null, total: 0 };
|
|
let olderRequest = null;
|
|
|
|
const validComments = comments => Array.isArray(comments)
|
|
? comments.filter(comment => comment && Number.isInteger(comment.id))
|
|
: [];
|
|
|
|
const unique = comments => {
|
|
const seen = new Set();
|
|
return comments.filter(comment => {
|
|
if (seen.has(comment.id)) return false;
|
|
seen.add(comment.id);
|
|
return true;
|
|
}).sort((left, right) => {
|
|
const leftTime = Date.parse(left.created_at || '');
|
|
const rightTime = Date.parse(right.created_at || '');
|
|
if (Number.isFinite(leftTime) && Number.isFinite(rightTime) && leftTime !== rightTime) {
|
|
return leftTime - rightTime;
|
|
}
|
|
return left.id - right.id;
|
|
});
|
|
};
|
|
|
|
const snapshot = () => ({ ...state, comments: state.comments.map(comment => ({ ...comment })) });
|
|
|
|
return {
|
|
reset(page) {
|
|
const comments = unique(validComments(page?.comments));
|
|
state = {
|
|
comments,
|
|
page: Number.isInteger(page?.page) ? page.page : 1,
|
|
older_page: Number.isInteger(page?.older_page) ? page.older_page : null,
|
|
total: Number.isInteger(page?.total) ? Math.max(page.total, comments.length) : comments.length,
|
|
};
|
|
olderRequest = null;
|
|
return snapshot();
|
|
},
|
|
snapshot,
|
|
loadOlder() {
|
|
if (olderRequest) return olderRequest;
|
|
if (!Number.isInteger(state.older_page)) return Promise.resolve(snapshot());
|
|
const requestedPage = state.older_page;
|
|
olderRequest = Promise.resolve(loadPage(requestedPage)).then(page => {
|
|
state = {
|
|
comments: unique(validComments(page?.comments).concat(state.comments)),
|
|
page: Number.isInteger(page?.page) ? page.page : requestedPage,
|
|
older_page: Number.isInteger(page?.older_page) ? page.older_page : null,
|
|
total: Number.isInteger(page?.total) ? Math.max(page.total, state.comments.length) : state.total,
|
|
};
|
|
return snapshot();
|
|
}).finally(() => { olderRequest = null; });
|
|
return olderRequest;
|
|
},
|
|
append(comment) {
|
|
if (!comment || !Number.isInteger(comment.id)) return snapshot();
|
|
if (!state.comments.some(existing => existing.id === comment.id)) {
|
|
state = {
|
|
...state,
|
|
comments: state.comments.concat(comment),
|
|
total: Math.max(state.total + 1, state.comments.length + 1),
|
|
};
|
|
}
|
|
return snapshot();
|
|
},
|
|
replace(comment) {
|
|
if (!comment || !Number.isInteger(comment.id)) return snapshot();
|
|
state = {
|
|
...state,
|
|
comments: state.comments.map(existing => existing.id === comment.id ? { ...comment } : existing),
|
|
};
|
|
return snapshot();
|
|
},
|
|
remove(commentId) {
|
|
const comments = state.comments.filter(comment => comment.id !== commentId);
|
|
if (comments.length !== state.comments.length) {
|
|
state = { ...state, comments, total: Math.max(0, state.total - 1) };
|
|
}
|
|
return snapshot();
|
|
},
|
|
};
|
|
}
|
|
|
|
if (typeof module !== 'undefined' && module.exports) module.exports = createConversationPager;
|