diff --git a/modules/rsocials/components/folk-thread-gallery.ts b/modules/rsocials/components/folk-thread-gallery.ts index 2b47e6c1..28810041 100644 --- a/modules/rsocials/components/folk-thread-gallery.ts +++ b/modules/rsocials/components/folk-thread-gallery.ts @@ -22,19 +22,30 @@ interface DraftPostCard { threadId?: string; } +type StatusFilter = 'all' | 'draft' | 'scheduled' | 'published'; +const STATUS_STORAGE_KEY = 'rsocials:gallery:status-filter'; + export class FolkThreadGallery extends HTMLElement { private _space = 'demo'; private _threads: ThreadData[] = []; - private _draftPosts: DraftPostCard[] = []; + private _allPosts: DraftPostCard[] = []; private _offlineUnsub: (() => void) | null = null; private _subscribedDocIds: string[] = []; private _isDemoFallback = false; + private _statusFilter: StatusFilter = 'all'; static get observedAttributes() { return ['space']; } connectedCallback() { if (!this.shadowRoot) this.attachShadow({ mode: 'open' }); this._space = this.getAttribute('space') || 'demo'; + // Restore last status filter + try { + const saved = localStorage.getItem(STATUS_STORAGE_KEY); + if (saved === 'draft' || saved === 'scheduled' || saved === 'published' || saved === 'all') { + this._statusFilter = saved; + } + } catch { /* ignore */ } this.render(); this.subscribeOffline(); } @@ -100,24 +111,23 @@ export class FolkThreadGallery extends HTMLElement { this._isDemoFallback = false; this._threads = Object.values(doc.threads).sort((a, b) => b.updatedAt - a.updatedAt); - // Extract draft/scheduled posts from campaigns - this._draftPosts = []; + // Extract all campaign posts across statuses so the status filter + // can choose between drafts / scheduled / published. + this._allPosts = []; if (doc.campaigns) { for (const campaign of Object.values(doc.campaigns)) { for (const post of campaign.posts || []) { - if (post.status === 'draft' || post.status === 'scheduled') { - this._draftPosts.push({ - id: post.id, - campaignId: campaign.id, - campaignTitle: campaign.title, - platform: post.platform, - content: post.content, - scheduledAt: post.scheduledAt, - status: post.status, - hashtags: post.hashtags || [], - threadId: post.threadId, - }); - } + this._allPosts.push({ + id: post.id, + campaignId: campaign.id, + campaignTitle: campaign.title, + platform: post.platform, + content: post.content, + scheduledAt: post.scheduledAt, + status: post.status, + hashtags: post.hashtags || [], + threadId: post.threadId, + }); } } } @@ -147,28 +157,63 @@ export class FolkThreadGallery extends HTMLElement { private render() { if (!this.shadowRoot) return; - const space = this._space; const threads = this._threads; - const drafts = this._draftPosts; + const filter = this._statusFilter; - const threadCardsHTML = threads.length === 0 && drafts.length === 0 + // Filter + sort posts by status + recency + const filteredPosts = this._allPosts + .filter(p => filter === 'all' || p.status === filter) + .sort((a, b) => { + const aT = a.scheduledAt ? new Date(a.scheduledAt).getTime() : 0; + const bT = b.scheduledAt ? new Date(b.scheduledAt).getTime() : 0; + return bT - aT; + }); + + // Status counts for chip badges + const counts = { + all: this._allPosts.length, + draft: this._allPosts.filter(p => p.status === 'draft').length, + scheduled: this._allPosts.filter(p => p.status === 'scheduled').length, + published: this._allPosts.filter(p => p.status === 'published').length, + }; + + const chip = (key: StatusFilter, label: string) => + ``; + + const filterBar = `
`; + + // Threads are shown only when status is "all" or "published" — they don't have draft state in this schema. + const showThreads = filter === 'all' || filter === 'published'; + const threadsVisible = showThreads ? threads : []; + + const threadCardsHTML = filteredPosts.length === 0 && threadsVisible.length === 0 ? `No posts or threads yet. Create your first thread!
- Create Thread +${filter === 'all' ? 'No posts or threads yet.' : `No ${filter} posts.`} Create your first post or thread.
+Social media tools for your community
- -