Skip to content

Commit

Permalink
Add multi-user support to BookmarkService
Browse files Browse the repository at this point in the history
  • Loading branch information
miladsoft committed Oct 31, 2024
1 parent 576b0fa commit 0954fae
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 62 deletions.
56 changes: 23 additions & 33 deletions src/app/components/bookmark/bookmark.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { RouterLink } from '@angular/router';
import { BookmarkService } from 'app/services/bookmark.service';
import { Project } from 'app/interface/project.interface';
import { StorageService } from 'app/services/storage.service';
import { Observable, Subject, Subscription, takeUntil } from 'rxjs';
import { Observable, Subject, takeUntil } from 'rxjs';

@Component({
selector: 'app-bookmark',
Expand All @@ -39,59 +39,52 @@ import { Observable, Subject, Subscription, takeUntil } from 'rxjs';
PercentPipe,
I18nPluralPipe,
CommonModule,

],
],
templateUrl: './bookmark.component.html',
styleUrl: './bookmark.component.scss'
styleUrls: ['./bookmark.component.scss']
})
export class BookmarkComponent implements OnInit, OnDestroy {
savedProjects: Project[] = [];
bookmarks$: Observable<string[]>;
private _unsubscribeAll: Subject<any> = new Subject<any>();
private _unsubscribeAll = new Subject<any>();

constructor(
private _bookmarkService: BookmarkService,
private _storageService: StorageService,
private _changeDetectorRef: ChangeDetectorRef
) {
this.bookmarks$ = this._bookmarkService.bookmarks$;
}

ngOnInit(): void {
this.loadBookmarkedProjects();
async ngOnInit(): Promise<void> {
await this._bookmarkService.initializeForCurrentUser(); // Clear previous bookmarks and load current user's bookmarks
await this.loadBookmarkedProjects();
this.subscribeToBookmarkChanges();
}


private loadBookmarkedProjects(): void {
const bookmarkIds = this._bookmarkService.getBookmarks();
this._storageService.getProjectsByIds(bookmarkIds).then((projects: Project[]) => {
this.savedProjects = projects;
this.fetchMetadataForProjects(this.savedProjects);
});
}


trackByFn(index: number, item: Project): string | number {
return item.projectIdentifier || index;
}

private async loadBookmarkedProjects(): Promise<void> {
const bookmarkIds = await this._bookmarkService.getBookmarks();
const projects = await this._storageService.getProjectsByIds(bookmarkIds);
this.savedProjects = projects;
this.fetchMetadataForProjects(this.savedProjects); // Fetch metadata for loaded projects
}

private subscribeToBookmarkChanges(): void {
this.bookmarks$.pipe(takeUntil(this._unsubscribeAll)).subscribe((bookmarkIds: string[]) => {
this._storageService.getProjectsByIds(bookmarkIds).then((projects: Project[]) => {
this.savedProjects = projects;
this.fetchMetadataForProjects(this.savedProjects);
});
this.bookmarks$.pipe(takeUntil(this._unsubscribeAll)).subscribe(async (bookmarkIds) => {
const projects = await this._storageService.getProjectsByIds(bookmarkIds);
this.savedProjects = projects;
this.fetchMetadataForProjects(this.savedProjects); // Fetch metadata for updated projects
});
}


private fetchMetadataForProjects(projects: Project[]): void {
projects.forEach(project => {
this._storageService.getProfile(project.nostrPubKey).then(profileMetadata => {
if (profileMetadata) {
this.updateProjectMetadata(project, profileMetadata);
this._changeDetectorRef.detectChanges();
}
});
});
Expand All @@ -104,18 +97,15 @@ export class BookmarkComponent implements OnInit, OnDestroy {
project.banner = metadata.banner || project.banner;
}

toggleBookmark(projectId: string): void {
if (this._bookmarkService.isBookmarked(projectId)) {
this._bookmarkService.removeBookmark(projectId);
async toggleBookmark(projectId: string): Promise<void> {
const isBookmarked = await this._bookmarkService.isBookmarked(projectId);
if (isBookmarked) {
await this._bookmarkService.removeBookmark(projectId);
} else {
this._bookmarkService.addBookmark(projectId);
await this._bookmarkService.addBookmark(projectId);
}
}

isProjectBookmarked(projectId: string): boolean {
return this._bookmarkService.isBookmarked(projectId);
}

ngOnDestroy(): void {
this._unsubscribeAll.next(null);
this._unsubscribeAll.complete();
Expand Down
15 changes: 8 additions & 7 deletions src/app/components/explore/explore.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,18 +264,19 @@ export class ExploreComponent implements OnInit, OnDestroy {
this.showCloseSearchButton = false;
}

toggleBookmark(projectId: string): void {
if (this._bookmarkService.isBookmarked(projectId)) {
this._bookmarkService.removeBookmark(projectId);
async toggleBookmark(projectId: string): Promise<void> {
const isBookmarked = await this._bookmarkService.isBookmarked(projectId);
if (isBookmarked) {
await this._bookmarkService.removeBookmark(projectId);
} else {
this._bookmarkService.addBookmark(projectId);
await this._bookmarkService.addBookmark(projectId);
}
}

isProjectBookmarked(projectId: string): boolean {
return this._bookmarkService.isBookmarked(projectId);
async isProjectBookmarked(projectId: string): Promise<boolean> {
return await this._bookmarkService.isBookmarked(projectId);
}

ngOnDestroy(): void {
this._unsubscribeAll.next(null);
this._unsubscribeAll.complete();
Expand Down
141 changes: 119 additions & 22 deletions src/app/services/bookmark.service.ts
Original file line number Diff line number Diff line change
@@ -1,51 +1,148 @@
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
import { SignerService } from './signer.service';

@Injectable({
providedIn: 'root',
})
export class BookmarkService {
private readonly STORAGE_KEY = 'bookmarkedProjects';
private readonly STORAGE_KEY = 'userBookmarkedProjects';
private bookmarksSubject = new BehaviorSubject<string[]>([]);
public bookmarks$ = this.bookmarksSubject.asObservable();
private currentUserPubKey: string | null = null;


private bookmarksSubject: BehaviorSubject<string[]> = new BehaviorSubject<string[]>(this.getBookmarks());
public bookmarks$: Observable<string[]> = this.bookmarksSubject.asObservable();

constructor() {
constructor(private _signerService: SignerService) {
// Listen to storage changes to keep bookmarks updated across tabs
window.addEventListener('storage', (event) => {
if (event.key === this.STORAGE_KEY) {

this.bookmarksSubject.next(this.getBookmarks());
this.refreshBookmarksForCurrentUser();
}
});
}

// Initialize bookmarks for the current user
async initializeForCurrentUser(): Promise<void> {
this.clearBookmarks(); // Clear any previous bookmarks
this.currentUserPubKey = await this._signerService.getPublicKey(); // Get current user's public key

if (this.currentUserPubKey) {
await this.loadBookmarksForCurrentUser();
}
}

// Clear current bookmarks to prevent showing previous user's data
private clearBookmarks(): void {
this.bookmarksSubject.next([]);
}

// Load bookmarks for the current user based on their public key
private async loadBookmarksForCurrentUser(): Promise<void> {
if (!this.currentUserPubKey) return;

getBookmarks(): string[] {
const allBookmarks = this.getUserBookmarks();
const userBookmarks = allBookmarks[this.currentUserPubKey] || [];
this.bookmarksSubject.next(userBookmarks); // Set bookmarks for current user
}

// Fetch all user bookmarks from localStorage
private getUserBookmarks(): { [pubKey: string]: string[] } {
const bookmarks = localStorage.getItem(this.STORAGE_KEY);
return bookmarks ? JSON.parse(bookmarks) : [];
return bookmarks ? JSON.parse(bookmarks) : {};
}

// Save bookmarks for the current user to localStorage
private saveUserBookmarks(bookmarks: { [pubKey: string]: string[] }): void {
localStorage.setItem(this.STORAGE_KEY, JSON.stringify(bookmarks));
}

// Add a bookmark for the current user
async addBookmark(projectId: string): Promise<void> {
if (!this.currentUserPubKey) {
this.currentUserPubKey = await this._signerService.getPublicKey();
if (!this.currentUserPubKey) {
console.warn('No public key found for the current user.');
return;
}
}

addBookmark(projectId: string): void {
const bookmarks = this.getBookmarks();
if (!bookmarks.includes(projectId)) {
bookmarks.push(projectId);
localStorage.setItem(this.STORAGE_KEY, JSON.stringify(bookmarks));
this.bookmarksSubject.next(bookmarks);
const allBookmarks = this.getUserBookmarks();
const userBookmarks = allBookmarks[this.currentUserPubKey] || [];

if (!userBookmarks.includes(projectId)) {
userBookmarks.push(projectId);
allBookmarks[this.currentUserPubKey] = userBookmarks;
this.saveUserBookmarks(allBookmarks);
this.bookmarksSubject.next(userBookmarks);
}
}

// Remove a bookmark for the current user
async removeBookmark(projectId: string): Promise<void> {
if (!this.currentUserPubKey) {
this.currentUserPubKey = await this._signerService.getPublicKey();
if (!this.currentUserPubKey) {
console.warn('No public key found for the current user.');
return;
}
}

const allBookmarks = this.getUserBookmarks();
const userBookmarks = allBookmarks[this.currentUserPubKey] || [];
const updatedBookmarks = userBookmarks.filter(id => id !== projectId);

removeBookmark(projectId: string): void {
const bookmarks = this.getBookmarks();
const updatedBookmarks = bookmarks.filter(id => id !== projectId);
localStorage.setItem(this.STORAGE_KEY, JSON.stringify(updatedBookmarks));
allBookmarks[this.currentUserPubKey] = updatedBookmarks;
this.saveUserBookmarks(allBookmarks);
this.bookmarksSubject.next(updatedBookmarks);
}

// Check if a project is bookmarked by the current user
async isBookmarked(projectId: string): Promise<boolean> {
if (!this.currentUserPubKey) {
this.currentUserPubKey = await this._signerService.getPublicKey();
if (!this.currentUserPubKey) {
console.warn('No public key found for the current user.');
return false;
}
}

const userBookmarks = this.getUserBookmarks()[this.currentUserPubKey] || [];
return userBookmarks.includes(projectId);
}

// Retrieve all bookmarks for the current user
async getBookmarks(): Promise<string[]> {
if (!this.currentUserPubKey) {
this.currentUserPubKey = await this._signerService.getPublicKey();
if (!this.currentUserPubKey) {
console.warn('No public key found for the current user.');
return [];
}
}

isBookmarked(projectId: string): boolean {
return this.getBookmarks().includes(projectId);
const allBookmarks = this.getUserBookmarks();
return allBookmarks[this.currentUserPubKey] || [];
}

// Remove all bookmarks for the current user
async removeAllBookmarks(): Promise<void> {
if (!this.currentUserPubKey) {
this.currentUserPubKey = await this._signerService.getPublicKey();
if (!this.currentUserPubKey) {
console.warn('No public key found for the current user.');
return;
}
}

const allBookmarks = this.getUserBookmarks();
allBookmarks[this.currentUserPubKey] = [];
this.saveUserBookmarks(allBookmarks);
this.bookmarksSubject.next([]);
}

// Refresh bookmarks for the current user when the storage event occurs
private refreshBookmarksForCurrentUser(): void {
if (this.currentUserPubKey) {
this.loadBookmarksForCurrentUser();
}
}
}

0 comments on commit 0954fae

Please sign in to comment.