Skip to content
Draft
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 43 additions & 4 deletions src/app/news/news-list.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ export class NewsListComponent implements OnInit, OnChanges, AfterViewInit, OnDe
}

ngOnChanges() {
this.isLoadingMore = false;
let isLatest = true;
this.replyObject = {};
this.items.forEach(item => {
Expand Down Expand Up @@ -121,7 +122,24 @@ export class NewsListComponent implements OnInit, OnChanges, AfterViewInit, OnDe

initNews() {
const newVoiceId = this.route.firstChild?.snapshot.paramMap.get('id') || 'root';
this.filterNewsToShow(newVoiceId);

// Check if voice is in the current items
if (newVoiceId !== 'root' && !this.items.find(item => item._id === newVoiceId)) {
this.newsService.getNewsById(newVoiceId).subscribe({
next: (newsItem) => {
if (!this.items.find(item => item._id === newsItem._id)) {
this.items = [ newsItem, ...this.items ];
this.ngOnChanges();
}
this.filterNewsToShow(newVoiceId);
},
error: () => {
this.filterNewsToShow('root');
}
});
} else {
this.filterNewsToShow(newVoiceId);
}
}

showReplies(news) {
Expand Down Expand Up @@ -312,10 +330,19 @@ export class NewsListComponent implements OnInit, OnChanges, AfterViewInit, OnDe
const news = this.getCurrentItems();
this.totalItems = news.length;
const start = this.pageIndex * this.pageSize;
const end = start + this.pageSize;
const { items } = this.paginateItems(news, start, this.pageSize);
this.displayedItems = items;

const shouldFetchRemote = (end >= news.length - this.pageSize) && this.newsService.canLoadMore();
if (shouldFetchRemote && !this.isLoadingMore) {
this.isLoadingMore = true;
this.newsService.loadMoreNews();
} else {
this.isLoadingMore = false;
}

this.hasMoreNews = false;
this.isLoadingMore = false;
} else {
let pageSize = this.pageSize;
if (initial) {
Expand All @@ -330,13 +357,25 @@ export class NewsListComponent implements OnInit, OnChanges, AfterViewInit, OnDe
this.displayedItems = [ ...this.displayedItems, ...items ];
this.pageEnd[this.replyViewing._id] = this.displayedItems.length;
this.nextStartIndex = endIndex;
this.hasMoreNews = hasMore;
this.isLoadingMore = false;
this.totalReplies = news.length;

const shouldFetchRemote = endIndex >= news.length && !hasMore && this.newsService.canLoadMore();

if (shouldFetchRemote) {
this.isLoadingMore = true;
this.newsService.loadMoreNews();
} else {
this.isLoadingMore = false;
}

this.hasMoreNews = hasMore || shouldFetchRemote || this.newsService.canLoadMore();
}
}

loadMoreItems() {
if (this.isLoadingMore) {
return;
}
this.isLoadingMore = true;
this.loadPagedItems(false);
}
Expand Down
126 changes: 110 additions & 16 deletions src/app/news/news.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ export class NewsService {
imgUrlPrefix = environment.couchAddress;
newsUpdated$ = new Subject<any[]>();
currentOptions: { selectors: any, viewId: string } = { selectors: {}, viewId: '' };
private currentBookmark: string | undefined;
private hasMoreResults = true;
private isLoading = false;
private pageSize = 50;
private accumulatedNews: any[] = [];
private avatarCache: Record<string, any> = {};

constructor(
private couchService: CouchService,
Expand All @@ -29,25 +35,22 @@ export class NewsService {

requestNews({ selectors, viewId } = this.currentOptions) {
this.currentOptions = { selectors, viewId };
this.couchService.findAll(this.dbName, findDocuments(selectors, 0, [ { 'time': 'desc' } ])).pipe(
switchMap((newsItems: any[]) =>
this.couchService.findAttachmentsByIds(this.collectAttachmentIds(newsItems)).pipe(
map((attachments: any[]) => ({
newsItems,
avatarMap: new Map<string, any>(attachments.map((attachment: any) => [ attachment._id, attachment ]))
}))
)
)
).subscribe(({ newsItems, avatarMap }) => {
this.newsUpdated$.next(newsItems.map((item: any) => (
{ doc: item, sharedDate: this.findShareDate(item, viewId), avatar: this.findAvatar(item.user, avatarMap), _id: item._id }
)));
});
this.resetPagination();
this.fetchNewsPage(true);
}

loadMoreNews() {
if (!this.canLoadMore()) { return; }
this.fetchNewsPage(false);
}

findAvatar(user: any, attachments: Map<string, any>) {
canLoadMore(): boolean {
return this.hasMoreResults && !this.isLoading;
}

findAvatar(user: any, attachments: Record<string, any>) {
const attachmentId = `${user._id}@${user.planetCode}`;
const attachment = attachments.get(attachmentId);
const attachment = attachments ? attachments[attachmentId] : undefined;
const extractFilename = (object) => Object.keys(object._attachments)[0];
return attachment ?
`${this.imgUrlPrefix}/attachments/${attachmentId}/${extractFilename(attachment)}` :
Expand All @@ -71,6 +74,73 @@ export class NewsService {
return Array.from(ids);
}

private resetPagination() {
this.currentBookmark = undefined;
this.hasMoreResults = true;
this.isLoading = false;
this.accumulatedNews = [];
this.avatarCache = {};
}

private fetchNewsPage(reset: boolean) {
const query: any = { ...findDocuments(this.currentOptions.selectors, 0, [ { 'time': 'desc' } ], this.pageSize) };
if (!reset && this.currentBookmark) {
query.bookmark = this.currentBookmark;
}
this.isLoading = true;
this.couchService.post(`${this.dbName}/_find`, query).subscribe({
next: (response: any) => {
const docs = response?.docs ?? [];
const bookmark = response?.bookmark;
this.isLoading = false;
this.currentBookmark = bookmark;
if (reset) {
this.accumulatedNews = [];
}
if (docs.length === 0) {
this.hasMoreResults = false;
this.emitNews();
return;
}
this.hasMoreResults = docs.length === this.pageSize && !!bookmark;
this.accumulatedNews = [ ...this.accumulatedNews, ...docs ];
this.emitNews();
this.loadMissingAttachments(docs);
},
error: () => {
this.isLoading = false;
this.hasMoreResults = false;
}
});
}

private loadMissingAttachments(newsItems: any[]) {
const missingIds = this.collectAttachmentIds(newsItems).filter(id => !(id in this.avatarCache));
if (missingIds.length === 0) {
return;
}
this.couchService.findAttachmentsByIds(missingIds).subscribe((attachments: any[]) => {
if (!attachments || attachments.length === 0) { return; }
attachments.forEach((attachment: any) => {
if (attachment && attachment._id) {
this.avatarCache[attachment._id] = attachment;
}
});
this.emitNews();
});
}

private emitNews() {
const viewId = this.currentOptions.viewId;
const formatted = this.accumulatedNews.map((item: any) => ({
doc: item,
sharedDate: this.findShareDate(item, viewId),
avatar: this.findAvatar(item.user, this.avatarCache),
_id: item._id
}));
this.newsUpdated$.next([ ...formatted ]);
}

postNews(post, successMessage = $localize`Thank you for submitting your message`, isMessageEdit = true) {
const { configuration } = this.stateService;
const message = typeof post.message === 'string' ? post.message : post.message.text;
Expand Down Expand Up @@ -146,4 +216,28 @@ export class NewsService {
return post && post.doc && (post.doc.viewIn || []).some(({ _id }) => _id === planetAndParentId(this.stateService.configuration));
}

getNewsById(newsId: string) {
return this.couchService.get(`${this.dbName}/${newsId}`).pipe(
switchMap((newsItem: any) => {
const attachmentIds = this.collectAttachmentIds([ newsItem ]);
return this.couchService.findAttachmentsByIds(attachmentIds).pipe(
map((attachments: any[]) => {
const avatarMap: Record<string, any> = {};
attachments.forEach(attachment => {
if (attachment && attachment._id) {
avatarMap[attachment._id] = attachment;
}
});
return {
doc: newsItem,
sharedDate: this.findShareDate(newsItem, this.currentOptions.viewId),
avatar: this.findAvatar(newsItem.user, avatarMap),
_id: newsItem._id
};
})
);
})
);
}

}
Loading