From f403c86eb1048cba09675c565b691b70766f777c Mon Sep 17 00:00:00 2001 From: Andre Coullard Date: Mon, 9 Mar 2026 23:58:38 -0400 Subject: [PATCH 1/5] initial ver --- components/moderation/News.tsx | 83 ++++++++++++++++++++++++++++ components/moderation/index.ts | 1 + components/moderation/moderation.tsx | 8 +++ firestore.rules | 6 ++ 4 files changed, 98 insertions(+) create mode 100644 components/moderation/News.tsx diff --git a/components/moderation/News.tsx b/components/moderation/News.tsx new file mode 100644 index 000000000..ea22b4e47 --- /dev/null +++ b/components/moderation/News.tsx @@ -0,0 +1,83 @@ +import React, { useEffect } from "react" +import { collection, getFirestore, onSnapshot } from "firebase/firestore" +import { + Create, + Datagrid, + DateField, + DateInput, + Edit, + EditButton, + List, + SelectInput, + SimpleForm, + TextField, + TextInput, + useRefresh +} from "react-admin" + +const typeChoices = [ + { id: "article", name: "Article" }, + { id: "award", name: "Award" }, + { id: "book", name: "Book" } +] + +export function ListNews() { + const firestore = getFirestore() + const refresh = useRefresh() + + useEffect(() => { + const newsRef = collection(firestore, "news") + const unsubscribe = onSnapshot( + newsRef, + () => refresh(), + (e: Error) => console.log(e) + ) + + return () => unsubscribe() + }, [firestore, refresh]) + + return ( + + + + + + + + + + + ) +} + +export function EditNews() { + return ( + + + + + + + + + + + ) +} + +export function CreateNews() { + return ( + ) => ({ ...data, createdAt: new Date() })}> + + + + + + + + + + ) +} + +export default { ListNews, EditNews, CreateNews } diff --git a/components/moderation/index.ts b/components/moderation/index.ts index f987db222..a4dd62883 100644 --- a/components/moderation/index.ts +++ b/components/moderation/index.ts @@ -1,5 +1,6 @@ export * from "./types" export * from "./ListPublishedTestimony" +export * from "./News" export * from "./ListReports" export * from "./EditReports" export * from "./ListProfiles" diff --git a/components/moderation/moderation.tsx b/components/moderation/moderation.tsx index f0926fc84..2ddc27834 100644 --- a/components/moderation/moderation.tsx +++ b/components/moderation/moderation.tsx @@ -5,6 +5,7 @@ import { QueryClient, QueryClientProvider } from "react-query" import { EditReports, ListReports } from "./" import { ListProfiles } from "./ListProfiles" import { ScrapeHearingList } from "./ScrapeHearing" +import { ListNews, EditNews, CreateNews } from "./" import { createMyOne, getMyListGroup, @@ -54,6 +55,13 @@ const App = () => { list={ScrapeHearingList} options={{ label: "Scrape Hearing" }} /> + ) diff --git a/firestore.rules b/firestore.rules index e33d279e2..5cbca817b 100644 --- a/firestore.rules +++ b/firestore.rules @@ -69,6 +69,12 @@ service cloud.firestore { // Only admins can do anything with it allow read, write: if request.auth.token.get("role", "user") == "admin" } + + // Admin-managed news collection used by the admin UI and public news page + match /news/{nid} { + allow read: if true; + allow write: if request.auth.token.get("role", "user") == "admin"; + } match /users/{uid} { allow read, write: if request.auth.token.get("role", "user") == "admin" match /draftTestimony/{id} { From c156ac4bffcbe6b7ba63f98612e28cd92814b818 Mon Sep 17 00:00:00 2001 From: Andre Coullard Date: Tue, 10 Mar 2026 02:36:13 -0400 Subject: [PATCH 2/5] tweaks and changes --- components/db/index.ts | 1 + components/db/news.ts | 26 ++++++++++++++++++++ components/moderation/News.tsx | 9 ++++++- components/moderation/dataProviderDbCalls.ts | 10 +++++--- 4 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 components/db/news.ts diff --git a/components/db/index.ts b/components/db/index.ts index 768d36da1..8a30079c1 100644 --- a/components/db/index.ts +++ b/components/db/index.ts @@ -1,6 +1,7 @@ export * from "./bills" export * from "./createTableHook" export * from "./members" +export * from "./news" export * from "./profile" export * from "./testimony" export * from "./useUpcomingBills" diff --git a/components/db/news.ts b/components/db/news.ts new file mode 100644 index 000000000..fb4dca211 --- /dev/null +++ b/components/db/news.ts @@ -0,0 +1,26 @@ +import { collection, getDocs, orderBy, Timestamp } from "firebase/firestore" +import { useAsync } from "react-async-hook" +import { firestore } from "../firebase" + +export type NewsType = "article" | "award" | "book" + +export type NewsItem = { + id: string + url: string + title: string + author: string + type: NewsType + description?: string + publishDate: string + createdAt: Timestamp +} + +export async function listNews(): Promise { + const newsRef = collection(firestore, "news") + const result = await getDocs(newsRef) + return result.docs.map(d => ({ id: d.id, ...d.data() } as NewsItem)) +} + +export function useNews() { + return useAsync(listNews, []) +} diff --git a/components/moderation/News.tsx b/components/moderation/News.tsx index ea22b4e47..4707eaad6 100644 --- a/components/moderation/News.tsx +++ b/components/moderation/News.tsx @@ -7,6 +7,7 @@ import { DateInput, Edit, EditButton, + FunctionField, List, SelectInput, SimpleForm, @@ -44,6 +45,12 @@ export function ListNews() { + { + return record.createdAt.toLocaleString() + }} + /> @@ -67,7 +74,7 @@ export function EditNews() { export function CreateNews() { return ( - ) => ({ ...data, createdAt: new Date() })}> + ) => ({ ...data, createdAt: new Date() })}> diff --git a/components/moderation/dataProviderDbCalls.ts b/components/moderation/dataProviderDbCalls.ts index a4ccc5fc0..ed745a236 100644 --- a/components/moderation/dataProviderDbCalls.ts +++ b/components/moderation/dataProviderDbCalls.ts @@ -136,9 +136,13 @@ export async function createMyOne( ): Promise { console.log("creating my one") const { data, meta } = params - const ref = doc(firestore, resource, data.id) - await setDoc(ref, data) - return { data: data } + const ref = data.id + ? doc(firestore, resource, data.id) + : doc(collection(firestore, resource)) + const id = ref.id + const newData = { ...data, id } + await setDoc(ref, newData) + return { data: newData } } export const getMyListGroup = async ( From d429ba3418417eefd9838a377abea436e95c9aa3 Mon Sep 17 00:00:00 2001 From: Andre Coullard Date: Tue, 10 Mar 2026 02:45:36 -0400 Subject: [PATCH 3/5] fix create date display --- components/moderation/News.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/components/moderation/News.tsx b/components/moderation/News.tsx index 4707eaad6..2a630fdb2 100644 --- a/components/moderation/News.tsx +++ b/components/moderation/News.tsx @@ -45,12 +45,7 @@ export function ListNews() { - { - return record.createdAt.toLocaleString() - }} - /> + From c4779398607c1cd2c5b900c59e96548c2d8cebf9 Mon Sep 17 00:00:00 2001 From: Andre Coullard Date: Sun, 15 Mar 2026 20:49:53 -0400 Subject: [PATCH 4/5] re-trigger CI From 219520cb1b6455e0d12a5bc8bf72dd00505e9fde Mon Sep 17 00:00:00 2001 From: Andre Coullard Date: Sun, 15 Mar 2026 21:19:09 -0400 Subject: [PATCH 5/5] fix formatting --- components/moderation/News.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/components/moderation/News.tsx b/components/moderation/News.tsx index 2a630fdb2..fdb63b92a 100644 --- a/components/moderation/News.tsx +++ b/components/moderation/News.tsx @@ -69,7 +69,13 @@ export function EditNews() { export function CreateNews() { return ( - ) => ({ ...data, createdAt: new Date() })}> + ) => ({ + ...data, + createdAt: new Date() + })} + >