replace localStorage with pglite for persistent data, force-add previously ignored lib/ files
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
import {
|
||||
type Poll,
|
||||
fetchCandidacyMandates,
|
||||
fetchPolls,
|
||||
fetchPollsByIds,
|
||||
fetchTopics,
|
||||
fetchVotes,
|
||||
} from "@/shared/lib/aw-api"
|
||||
|
||||
export interface FeedTopicRef {
|
||||
label: string
|
||||
url: string | null
|
||||
}
|
||||
|
||||
export interface FeedItem {
|
||||
id: string
|
||||
kind: "poll"
|
||||
status: "upcoming" | "past"
|
||||
title: string
|
||||
url: string | null
|
||||
date: string | null
|
||||
topics: FeedTopicRef[]
|
||||
source: string
|
||||
}
|
||||
|
||||
function classifyPoll(poll: Poll): "upcoming" | "past" {
|
||||
// field_accepted is only present on completed votes
|
||||
if (poll.field_accepted != null) return "past"
|
||||
if (!poll.field_poll_date) return "upcoming"
|
||||
const today = new Date().toISOString().slice(0, 10)
|
||||
return poll.field_poll_date > today ? "upcoming" : "past"
|
||||
}
|
||||
|
||||
export async function assembleFeed(followedTopicIDs: number[], followedPoliticianIDs: number[]): Promise<FeedItem[]> {
|
||||
const [topics, polls] = await Promise.all([fetchTopics(), fetchPolls(150)])
|
||||
const topicMap = new Map(topics.map((t) => [t.id, t.label]))
|
||||
|
||||
const topicSet = new Set(followedTopicIDs)
|
||||
const filteredByTopics = topicSet.size > 0 ? polls.filter((p) => p.field_topics.some((t) => topicSet.has(t.id))) : []
|
||||
|
||||
const politicianPolls = await fetchPollsForPoliticians(followedPoliticianIDs)
|
||||
|
||||
const combined = new Map<number, Poll>()
|
||||
for (const p of [...filteredByTopics, ...politicianPolls]) combined.set(p.id, p)
|
||||
|
||||
const items: FeedItem[] = Array.from(combined.values()).map((poll) => ({
|
||||
id: `poll-${poll.id}`,
|
||||
kind: "poll",
|
||||
status: classifyPoll(poll),
|
||||
title: poll.label,
|
||||
url: poll.abgeordnetenwatch_url ?? null,
|
||||
date: poll.field_poll_date,
|
||||
topics: poll.field_topics.flatMap((t) => {
|
||||
const label = t.label ?? topicMap.get(t.id)
|
||||
return label ? [{ label, url: t.abgeordnetenwatch_url ?? null }] : []
|
||||
}),
|
||||
source: "Bundestag",
|
||||
}))
|
||||
|
||||
return items.sort((a, b) => {
|
||||
if (a.date && b.date) return b.date.localeCompare(a.date)
|
||||
if (!a.date && b.date) return 1
|
||||
if (a.date && !b.date) return -1
|
||||
return a.title.localeCompare(b.title)
|
||||
})
|
||||
}
|
||||
|
||||
async function fetchPollsForPoliticians(politicianIDs: number[]): Promise<Poll[]> {
|
||||
if (politicianIDs.length === 0) return []
|
||||
|
||||
const mandateResults = await Promise.all(politicianIDs.map((pid) => fetchCandidacyMandates(pid)))
|
||||
const mandateIDs = mandateResults.flatMap((mandates) => mandates.slice(0, 3).map((m) => m.id))
|
||||
|
||||
const voteResults = await Promise.all(mandateIDs.map((mid) => fetchVotes(mid)))
|
||||
const pollIDSet = new Set<number>()
|
||||
for (const votes of voteResults) {
|
||||
for (const v of votes) {
|
||||
if (v.poll?.id != null) pollIDSet.add(v.poll.id)
|
||||
}
|
||||
}
|
||||
|
||||
return fetchPollsByIds(Array.from(pollIDSet))
|
||||
}
|
||||
Reference in New Issue
Block a user