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 new file mode 100644 index 000000000..fdb63b92a --- /dev/null +++ b/components/moderation/News.tsx @@ -0,0 +1,91 @@ +import React, { useEffect } from "react" +import { collection, getFirestore, onSnapshot } from "firebase/firestore" +import { + Create, + Datagrid, + DateField, + DateInput, + Edit, + EditButton, + FunctionField, + 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/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 ( 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} {