story-research-zapwall/lib/articleFiltering.ts
Nicolas Cantu 3000872dbc refactoring
- **Motivations :** Assurer passage du lint strict et clarifier la logique paiements/publications.

- **Root causes :** Fonctions trop longues, promesses non gérées et typages WebLN/Nostr incomplets.

- **Correctifs :** Refactor PaymentModal (handlers void), extraction helpers articlePublisher, simplification polling sponsoring/zap, corrections curly et awaits.

- **Evolutions :** Nouveau module articlePublisherHelpers pour présentation/aiguillage contenu privé.

- **Page affectées :** components/PaymentModal.tsx, lib/articlePublisher.ts, lib/articlePublisherHelpers.ts, lib/paymentPolling.ts, lib/sponsoring.ts, lib/nostrZapVerification.ts et dépendances liées.
2025-12-22 17:56:00 +01:00

132 lines
3.8 KiB
TypeScript

import type { Article } from '@/types/nostr'
import type { ArticleFilters, SortOption } from '@/components/ArticleFilters'
/**
* Filter articles based on search query
*/
export function filterArticlesBySearch(articles: Article[], searchQuery: string): Article[] {
if (!searchQuery.trim()) {
return articles
}
const query = searchQuery.toLowerCase().trim()
return articles.filter((article) => {
const titleMatch = article.title.toLowerCase().includes(query)
const previewMatch = article.preview.toLowerCase().includes(query)
const contentMatch = article.content.toLowerCase().includes(query)
return titleMatch || previewMatch || contentMatch
})
}
/**
* Filter articles based on filters (author, price, category)
*/
export function filterArticles(articles: Article[], filters: ArticleFilters): Article[] {
let filtered = articles
// Exclude presentation articles from standard article lists
filtered = filtered.filter((article) => !article.isPresentation)
// Filter by category
if (filters.category && filters.category !== 'all') {
filtered = filtered.filter((article) => article.category === filters.category)
}
// Filter by author
if (filters.authorPubkey) {
filtered = filtered.filter((article) => article.pubkey === filters.authorPubkey)
}
// Filter by min price
if (filters.minPrice !== null) {
const minPrice = filters.minPrice
filtered = filtered.filter((article) => article.zapAmount >= minPrice)
}
// Filter by max price
if (filters.maxPrice !== null) {
const maxPrice = filters.maxPrice
filtered = filtered.filter((article) => article.zapAmount <= maxPrice)
}
return filtered
}
/**
* Get author sponsoring from their presentation article
* We need to look up the sponsoring from presentation articles
* For now, we'll use a cache or extract from already loaded articles
*/
function getAuthorSponsoringFromCache(
pubkey: string,
presentationArticles: Map<string, Article>
): number {
const presentation = presentationArticles.get(pubkey)
return presentation?.isPresentation ? presentation.totalSponsoring ?? 0 : 0
}
/**
* Sort articles based on sort option
* Default sort: by sponsoring (descending) then by date (newest first)
*/
export function sortArticles(
articles: Article[],
sortBy: SortOption,
presentationArticles?: Map<string, Article>
): Article[] {
const sorted = [...articles]
const presentationMap = presentationArticles ?? new Map<string, Article>()
switch (sortBy) {
case 'oldest':
return sorted.sort((a, b) => a.createdAt - b.createdAt)
case 'price-low':
return sorted.sort((a, b) => a.zapAmount - b.zapAmount)
case 'price-high':
return sorted.sort((a, b) => b.zapAmount - a.zapAmount)
case 'newest':
default:
// Default: sort by sponsoring (descending) then by date (newest first)
return sorted.sort((a, b) => {
const sponsoringA = getAuthorSponsoringFromCache(a.pubkey, presentationMap)
const sponsoringB = getAuthorSponsoringFromCache(b.pubkey, presentationMap)
// First sort by sponsoring (descending)
if (sponsoringA !== sponsoringB) {
return sponsoringB - sponsoringA
}
// Then sort by date (newest first)
return b.createdAt - a.createdAt
})
}
}
/**
* Apply all filters and sorting to articles
*/
export function applyFiltersAndSort(
articles: Article[],
searchQuery: string,
filters: ArticleFilters,
presentationArticles?: Map<string, Article>
): Article[] {
let result = articles
// First apply search filter
result = filterArticlesBySearch(result, searchQuery)
// Then apply other filters
result = filterArticles(result, filters)
// Finally apply sorting (with presentation articles for sponsoring lookup)
result = sortArticles(result, filters.sortBy, presentationArticles)
return result
}