From a9c2645c90c232d762ed5fb0bd791bbadc93d0a1 Mon Sep 17 00:00:00 2001 From: Arun Raman Date: Tue, 11 Jun 2024 18:47:31 -0400 Subject: [PATCH 01/26] Added some org skeleton code for now --- .../src/notifications/publishNotifications.ts | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/functions/src/notifications/publishNotifications.ts b/functions/src/notifications/publishNotifications.ts index d6f7f1858..91a70dfa0 100644 --- a/functions/src/notifications/publishNotifications.ts +++ b/functions/src/notifications/publishNotifications.ts @@ -112,6 +112,49 @@ export const publishNotifications = functions.firestore }) } + else if (topic.type == "org") { + // console.log('org') + + // const handleOrgNotifications = async (topic: { court: any; id: string; name: string; history: string; lastUpdatedTime: any }) => { + // const notificationFields = createNotificationFields( + // topic, + // "org" + // ) + + // console.log(JSON.stringify(notificationFields)) + + // const subscriptionsSnapshot = await db + // .collectionGroup("activeTopicSubscriptions") + // .where("topicName", "==", notificationFields.topicName) + // .get() + + // subscriptionsSnapshot.docs.forEach(doc => { + // const subscription = doc.data() + // const { uid } = subscription + + // // Add the uid to the notification document + // notificationFields.uid = uid + + // console.log(`Pushing notifications to users/${uid}/userNotificationFeed`) + + // // Create a notification document in the user's notification feed + // notificationPromises.push( + // db + // .collection(`users/${uid}/userNotificationFeed`) + // .add(notificationFields) + // ) + // }) + // } + + // await handleOrgNotifications({ + // court: topic.court, + // id: topic.id, + // name: topic.name, + // history: JSON.stringify(topic.history), + // lastUpdatedTime: topic.historyUpdateTime + // }) + } + // Wait for all notification documents to be created await Promise.all(notificationPromises) }) From 67b465f267074a6a8b7e765a160ccb9d1a69eae4 Mon Sep 17 00:00:00 2001 From: Arun Raman Date: Tue, 11 Jun 2024 20:39:28 -0400 Subject: [PATCH 02/26] Added seedNotificationEvents script --- .../populateNotificationEvents.ts | 2 +- .../firebase-admin/seedNotificationEvents.ts | 50 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 scripts/firebase-admin/seedNotificationEvents.ts diff --git a/functions/src/notifications/populateNotificationEvents.ts b/functions/src/notifications/populateNotificationEvents.ts index 6602ae3b4..ee3449aa4 100644 --- a/functions/src/notifications/populateNotificationEvents.ts +++ b/functions/src/notifications/populateNotificationEvents.ts @@ -12,7 +12,7 @@ import { BillHistory } from "../bills/types" // Get a reference to the Firestore database const db = admin.firestore() -type Notification = { +export type Notification = { type: string court: string id: string diff --git a/scripts/firebase-admin/seedNotificationEvents.ts b/scripts/firebase-admin/seedNotificationEvents.ts new file mode 100644 index 000000000..72fc7cf95 --- /dev/null +++ b/scripts/firebase-admin/seedNotificationEvents.ts @@ -0,0 +1,50 @@ +import { Timestamp } from "functions/src/firebase"; +import { Script } from "./types"; +import { Notification } from "functions/src/notifications/populateNotificationEvents"; +import { Record, Number } from "runtypes"; + +const Args = Record({ + court: Number +}); + +export const script: Script = async ({ db, args }) => { + console.log(args) + + const a = Args.check(args); + const court = a.court.toString(); + + const snapshot = await db.collection(`/generalCourts/${court}/bills`).get(); + + const batchLimit = 500; + let batch = db.batch(); + let operationCount = 0; + + for (const doc of snapshot.docs) { + const data = doc.data(); + + if (data) { + const notificationEvent: Notification = { + type: "bill", + court: court, + id: data.id, + name: data.id, + history: data.history, + historyUpdateTime: Timestamp.now(), + }; + + const ref = db.collection("/notificationEvents").doc(); + batch.set(ref, notificationEvent); + operationCount++; + + if (operationCount === batchLimit) { + await batch.commit(); + batch = db.batch(); + operationCount = 0; + } + } + } + + if (operationCount > 0) { + await batch.commit(); + } +}; From 49bc04cfc0e34ba62e7ca78e9ef8f747dde319d8 Mon Sep 17 00:00:00 2001 From: Arun Raman Date: Tue, 23 Jul 2024 20:36:36 -0400 Subject: [PATCH 03/26] Split each history --- .../src/notifications/publishNotifications.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/functions/src/notifications/publishNotifications.ts b/functions/src/notifications/publishNotifications.ts index 400fb7413..495526338 100644 --- a/functions/src/notifications/publishNotifications.ts +++ b/functions/src/notifications/publishNotifications.ts @@ -7,6 +7,7 @@ import * as functions from "firebase-functions" import * as admin from "firebase-admin" import { Timestamp } from "../firebase" +import { BillHistoryAction } from "../bills/types" // Get a reference to the Firestore database const db = admin.firestore() @@ -113,11 +114,22 @@ export const publishNotifications = functions.firestore }) } + // await handleBillNotifications({ + // court: topic.court, + // id: topic.id, + // name: topic.name, + // history: JSON.stringify(topic.history), + // lastUpdatedTime: topic.historyUpdateTime + // }) + + let recentBillAction: BillHistoryAction = topic.history[topic.history.length - 1] + let historyStr = `${recentBillAction.Branch} - ${recentBillAction.Action}` + await handleBillNotifications({ court: topic.court, id: topic.id, name: topic.name, - history: JSON.stringify(topic.history), + history: historyStr, lastUpdatedTime: topic.historyUpdateTime }) } From 32cc7df8d8f30562168d4c912b9234194ca84ff1 Mon Sep 17 00:00:00 2001 From: John Connery Date: Tue, 30 Jul 2024 02:23:41 -0400 Subject: [PATCH 04/26] Got newsfeed working --- .../src/notifications/publishNotifications.ts | 17 ++++---- scripts/firebase-admin/generateBillHistory.ts | 40 +++++++++++++++++++ 2 files changed, 48 insertions(+), 9 deletions(-) create mode 100644 scripts/firebase-admin/generateBillHistory.ts diff --git a/functions/src/notifications/publishNotifications.ts b/functions/src/notifications/publishNotifications.ts index 400fb7413..ce8440184 100644 --- a/functions/src/notifications/publishNotifications.ts +++ b/functions/src/notifications/publishNotifications.ts @@ -7,6 +7,7 @@ import * as functions from "firebase-functions" import * as admin from "firebase-admin" import { Timestamp } from "../firebase" +import { BillHistoryAction } from "../bills/types" // Get a reference to the Firestore database const db = admin.firestore() @@ -16,7 +17,7 @@ const createNotificationFields = ( court: any id: string name: string - history: string + history: BillHistoryAction lastUpdatedTime: any }, // history is an array, it needs to be concatenated type: string @@ -44,15 +45,15 @@ const createNotificationFields = ( topicName, uid: "", // user id will be populated in the publishNotifications function notification: { - bodyText: entity.history, // may change depending on event type + bodyText: `${entity.history.Action}`, // may change depending on event type header, id: entity.id, - subheader: "Do we need a sub heading", // may change depending on event type + subheader: `${entity.history.Branch}`, // may change depending on event type timestamp: entity.lastUpdatedTime, // could also be fullDate ; might need to remove this all together type, court, delivered: false - }, + }, createdAt: Timestamp.now() } } @@ -81,7 +82,7 @@ export const publishNotifications = functions.firestore court: any id: string name: string - history: string + history: BillHistoryAction lastUpdatedTime: any }) => { const notificationFields = createNotificationFields(topic, "bill") @@ -100,9 +101,7 @@ export const publishNotifications = functions.firestore // Add the uid to the notification document notificationFields.uid = uid - console.log( - `Pushing notifications to users/${uid}/userNotificationFeed` - ) + console.log(`Pushing notifications to users/${uid}/userNotificationFeed`) // Create a notification document in the user's notification feed notificationPromises.push( @@ -117,7 +116,7 @@ export const publishNotifications = functions.firestore court: topic.court, id: topic.id, name: topic.name, - history: JSON.stringify(topic.history), + history: topic.history[topic.history.length - 1], lastUpdatedTime: topic.historyUpdateTime }) } diff --git a/scripts/firebase-admin/generateBillHistory.ts b/scripts/firebase-admin/generateBillHistory.ts new file mode 100644 index 000000000..4869a387d --- /dev/null +++ b/scripts/firebase-admin/generateBillHistory.ts @@ -0,0 +1,40 @@ +import { Timestamp, FieldValue } from "../../functions/src/firebase" +import { Record, String, Number } from "runtypes" +import { Script } from "./types" +import { BillHistoryAction } from "../../functions/src/bills/types" + +const Args = Record({ + court: Number, + bills: String +}) + +export const script: Script = async ({ db, args }) => { + const a = Args.check(args) + const bills = a.bills.split(" ") + const court = a.court + let batch = db.batch() + let opsCounter = 0 + + for (const id of bills) { + const billHistoryAction: BillHistoryAction = { + Date: Timestamp.now().valueOf(), + Branch: Math.random() < 0.5 ? 'Senate' : 'House', + Action: (Math.random() + 1).toString(36).substring(2) + } + + const billRef = db.collection(`/generalCourts/${court}/bills`).doc(`${id}`) + batch.update(billRef, { history: FieldValue.arrayUnion(billHistoryAction) }) + opsCounter++ + + if (opsCounter % 500 === 0) { + await batch.commit() + batch = db.batch() + } + } + + if (opsCounter % 500 !== 0) { + await batch.commit() + } + + console.log(`Batch of ${opsCounter} bills updated.`) +} \ No newline at end of file From c8c5c9f042b9f34b661bc60f4a537e7a58428715 Mon Sep 17 00:00:00 2001 From: John Connery Date: Tue, 30 Jul 2024 02:26:21 -0400 Subject: [PATCH 05/26] Removed redundant code --- functions/src/notifications/publishNotifications.ts | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/functions/src/notifications/publishNotifications.ts b/functions/src/notifications/publishNotifications.ts index 809400178..ce8440184 100644 --- a/functions/src/notifications/publishNotifications.ts +++ b/functions/src/notifications/publishNotifications.ts @@ -112,17 +112,6 @@ export const publishNotifications = functions.firestore }) } - // await handleBillNotifications({ - // court: topic.court, - // id: topic.id, - // name: topic.name, - // history: JSON.stringify(topic.history), - // lastUpdatedTime: topic.historyUpdateTime - // }) - - let recentBillAction: BillHistoryAction = topic.history[topic.history.length - 1] - let historyStr = `${recentBillAction.Branch} - ${recentBillAction.Action}` - await handleBillNotifications({ court: topic.court, id: topic.id, From 5f2b01bbe353ab2761df4b0cd3862c200051e19f Mon Sep 17 00:00:00 2001 From: John Connery Date: Tue, 20 Aug 2024 03:00:27 -0400 Subject: [PATCH 06/26] User/org following wip --- functions/src/index.ts | 3 +- functions/src/notifications/index.ts | 6 +- ...s.ts => populateBillNotificationEvents.ts} | 48 +++-- .../populateOrgNotificationEvents.ts | 91 +++++++++ .../src/notifications/publishNotifications.ts | 176 ++++++------------ ...s.ts => backfillBillNotificationEvents.ts} | 20 +- 6 files changed, 204 insertions(+), 140 deletions(-) rename functions/src/notifications/{populateNotificationEvents.ts => populateBillNotificationEvents.ts} (72%) create mode 100644 functions/src/notifications/populateOrgNotificationEvents.ts rename scripts/firebase-admin/{seedNotificationEvents.ts => backfillBillNotificationEvents.ts} (77%) diff --git a/functions/src/index.ts b/functions/src/index.ts index 3ed4db170..a351822bc 100644 --- a/functions/src/index.ts +++ b/functions/src/index.ts @@ -32,7 +32,8 @@ export { } from "./testimony" export { publishNotifications, - populateNotificationEvents, + populateBillNotificationEvents, + populateOrgNotificationEvents, cleanupNotifications, deliverNotifications, httpsPublishNotifications, diff --git a/functions/src/notifications/index.ts b/functions/src/notifications/index.ts index dda66127a..bd66dec64 100644 --- a/functions/src/notifications/index.ts +++ b/functions/src/notifications/index.ts @@ -1,6 +1,7 @@ // Import the functions import { publishNotifications } from "./publishNotifications" -import { populateNotificationEvents } from "./populateNotificationEvents" +import { populateBillNotificationEvents } from "./populateBillNotificationEvents" +import { populateOrgNotificationEvents } from "./populateOrgNotificationEvents" import { cleanupNotifications } from "./cleanupNotifications" import { deliverNotifications } from "./deliverNotifications" import { httpsPublishNotifications } from "./httpsPublishNotifications" @@ -12,7 +13,8 @@ import { updateNextDigestAt } from "./updateNextDigestAt" // Export the functions export { publishNotifications, - populateNotificationEvents, + populateBillNotificationEvents, + populateOrgNotificationEvents, cleanupNotifications, deliverNotifications, httpsPublishNotifications, diff --git a/functions/src/notifications/populateNotificationEvents.ts b/functions/src/notifications/populateBillNotificationEvents.ts similarity index 72% rename from functions/src/notifications/populateNotificationEvents.ts rename to functions/src/notifications/populateBillNotificationEvents.ts index ee3449aa4..adad4ca29 100644 --- a/functions/src/notifications/populateNotificationEvents.ts +++ b/functions/src/notifications/populateBillNotificationEvents.ts @@ -14,15 +14,23 @@ const db = admin.firestore() export type Notification = { type: string - court: string - id: string - name: string - history: BillHistory - historyUpdateTime: Timestamp + + billCourt: string + billId: string + billName: string + + billHistory: BillHistory + + testimonyUser: string + testimonyPosition: string + testimonyContent: string + testimonyVersion: number + + updateTime: Timestamp } -// Define the populateNotificationEvents function -export const populateNotificationEvents = functions.firestore +// Define the populateBillNotificationEvents function +export const populateBillNotificationEvents = functions.firestore .document("/generalCourts/{court}/bills/{billId}") .onWrite(async (snapshot, context) => { if (!snapshot.after.exists) { @@ -43,11 +51,19 @@ export const populateNotificationEvents = functions.firestore const newNotificationEvent: Notification = { type: "bill", - court: court, - id: newData?.id, - name: newData?.id, - history: newData?.history, - historyUpdateTime: Timestamp.now() + + billCourt: court, + billId: newData?.id, + billName: newData?.id, + + billHistory: newData?.history, + + testimonyUser: "", + testimonyPosition: "", + testimonyContent: "", + testimonyVersion: -1, + + updateTime: Timestamp.now(), } await db.collection("/notificationEvents").add(newNotificationEvent) @@ -63,7 +79,9 @@ export const populateNotificationEvents = functions.firestore const notificationEventSnapshot = await db .collection("/notificationEvents") - .where("name", "==", newData?.id) + .where("type", "==", "bill") + .where("billCourt", "==", court) + .where("billId", "==", newData?.id) .get() console.log( @@ -81,8 +99,8 @@ export const populateNotificationEvents = functions.firestore .collection("/notificationEvents") .doc(notificationEventId) .update({ - history: newData?.history, - historyUpdateTime: Timestamp.now() + billHistory: newData?.history, + updateTime: Timestamp.now(), }) } } diff --git a/functions/src/notifications/populateOrgNotificationEvents.ts b/functions/src/notifications/populateOrgNotificationEvents.ts new file mode 100644 index 000000000..caa559509 --- /dev/null +++ b/functions/src/notifications/populateOrgNotificationEvents.ts @@ -0,0 +1,91 @@ +// Sets up a document trigger for /events and queries the activeTopicSubscriptions collection group in Firestore +// for all subscriptions for the given topic event, then creates a notification document in the user's notification feed. +// This function runs every time a new topic event is created in the /events collection. +// Creates a notification document in the user's notification feed for each active subscription. + +// Import necessary Firebase modules +import * as functions from "firebase-functions" +import * as admin from "firebase-admin" +import { Timestamp } from "../firebase" +import { Notification } from "./populateBillNotificationEvents" + +// Get a reference to the Firestore database +const db = admin.firestore() + +// Define the populateBillNotificationEvents function +export const populateOrgNotificationEvents = functions.firestore + .document("/users/{userId}/publishedTestimony/{testimonyId}") + .onWrite(async (snapshot, context) => { + if (!snapshot.after.exists) { + console.error("New snapshot does not exist") + return + } + + const documentCreated = !snapshot.before.exists + + const oldData = snapshot.before.data() + const newData = snapshot.after.data() + + // New testimony added + if (documentCreated) { + console.log("New document created") + + const newNotificationEvent: Notification = { + type: "org", + + billCourt: newData?.court.toString(), + billId: newData?.id, + billName: newData?.id, + + billHistory: [], + + testimonyUser: newData?.fullName, + testimonyPosition: newData?.position, + testimonyContent: newData?.content, + testimonyVersion: newData?.version, + + updateTime: Timestamp.now() + } + + await db.collection("/notificationEvents").add(newNotificationEvent) + + return + } + + const oldVersion = oldData?.version + const newVersion = newData?.version + + const testimonyChanged = oldVersion !== newVersion + console.log(`oldVersion: ${oldVersion}, newVersion: ${newVersion}`) + + const notificationEventSnapshot = await db + .collection("/notificationEvents") + .where("type", "==", "org") + .where("billCourt", "==", newData?.court.toString()) + .where("billId", "==", newData?.id) + .where("fullName", "==", newData?.fullName) + .get() + + console.log( + `${notificationEventSnapshot.docs} ${notificationEventSnapshot.docs.length}` + ) + + if (!notificationEventSnapshot.empty) { + const notificationEventId = notificationEventSnapshot.docs[0].id + + if (testimonyChanged) { + console.log("Testimony changed") + + // Update the existing notification event + await db + .collection("/notificationEvents") + .doc(notificationEventId) + .update({ + testimonyPosition: newData?.position, + testimonyContent: newData?.content, + testimonyVersion: newData?.version, + updateTime: Timestamp.now(), + }) + } + } + }) diff --git a/functions/src/notifications/publishNotifications.ts b/functions/src/notifications/publishNotifications.ts index ce8440184..1e8272c2e 100644 --- a/functions/src/notifications/publishNotifications.ts +++ b/functions/src/notifications/publishNotifications.ts @@ -7,50 +7,54 @@ import * as functions from "firebase-functions" import * as admin from "firebase-admin" import { Timestamp } from "../firebase" -import { BillHistoryAction } from "../bills/types" +import { Notification } from "./populateBillNotificationEvents" // Get a reference to the Firestore database const db = admin.firestore() -const createNotificationFields = ( - entity: { - court: any - id: string - name: string - history: BillHistoryAction - lastUpdatedTime: any - }, // history is an array, it needs to be concatenated - type: string -) => { - let topicName = "" - let header = "" - let court = null - switch (type) { +const createNotificationFields = (entity: Notification) => { + let topicName: string + let header: string + let court: string | null = null + let bodyText: string + let subheader: string + + switch (entity.type) { case "bill": - topicName = `bill-${entity.court}-${entity.id}` // looks for fields in event document - header = entity.name - court = entity.court + topicName = `bill-${entity.billCourt}-${entity.billId}` + header = entity.billId + court = entity.billCourt + if (entity.billHistory.length < 1) { + console.log(`Invalid history length: ${entity.billHistory.length}`) + throw new Error(`Invalid history length: ${entity.billHistory.length}`) + } + let lastHistoryAction = entity.billHistory[entity.billHistory.length - 1] + bodyText = `${lastHistoryAction.Action}` + subheader = `${lastHistoryAction.Branch}` break + case "org": - topicName = `org-${entity.id}` - header = entity.name + topicName = `org-${entity.testimonyUser}` + header = entity.billName + bodyText = entity.testimonyContent + subheader = entity.testimonyUser break + default: - // handle exception for entities that don't fit schema - console.log(`Invalid entity type: ${type}`) - throw new Error(`Invalid entity type: ${type}`) + console.log(`Invalid entity type: ${entity.type}`) + throw new Error(`Invalid entity type: ${entity.type}`) } + return { - // set up notification document fields topicName, - uid: "", // user id will be populated in the publishNotifications function + uid: "", notification: { - bodyText: `${entity.history.Action}`, // may change depending on event type + bodyText: bodyText, header, - id: entity.id, - subheader: `${entity.history.Branch}`, // may change depending on event type - timestamp: entity.lastUpdatedTime, // could also be fullDate ; might need to remove this all together - type, + id: entity.billId, + subheader: subheader, + timestamp: entity.updateTime, + type: entity.type, court, delivered: false }, @@ -63,7 +67,7 @@ export const publishNotifications = functions.firestore .document("/notificationEvents/{topicEventId}") .onWrite(async (snapshot, context) => { // Get the newly created topic event data - const topic = snapshot?.after.data() + const topic = snapshot?.after.data() as Notification | undefined if (!topic) { console.error("Invalid topic data:", topic) @@ -71,98 +75,38 @@ export const publishNotifications = functions.firestore } // Extract related Bill or Org data from the topic event - const notificationPromises: any[] = [] console.log(`topic type: ${topic.type}`) - if (topic.type == "bill") { - console.log("bill") - - const handleBillNotifications = async (topic: { - court: any - id: string - name: string - history: BillHistoryAction - lastUpdatedTime: any - }) => { - const notificationFields = createNotificationFields(topic, "bill") - - console.log(JSON.stringify(notificationFields)) - - const subscriptionsSnapshot = await db - .collectionGroup("activeTopicSubscriptions") - .where("topicName", "==", notificationFields.topicName) - .get() - - subscriptionsSnapshot.docs.forEach(doc => { - const subscription = doc.data() - const { uid } = subscription - - // Add the uid to the notification document - notificationFields.uid = uid - - console.log(`Pushing notifications to users/${uid}/userNotificationFeed`) - - // Create a notification document in the user's notification feed - notificationPromises.push( - db - .collection(`users/${uid}/userNotificationFeed`) - .add(notificationFields) - ) - }) - } + const handleNotifications = async (topic: Notification) => { + const notificationFields = createNotificationFields(topic) - await handleBillNotifications({ - court: topic.court, - id: topic.id, - name: topic.name, - history: topic.history[topic.history.length - 1], - lastUpdatedTime: topic.historyUpdateTime + console.log(JSON.stringify(notificationFields)) + + const subscriptionsSnapshot = await db + .collectionGroup("activeTopicSubscriptions") + .where("topicName", "==", notificationFields.topicName) + .get() + + subscriptionsSnapshot.docs.forEach(doc => { + const subscription = doc.data() + const { uid } = subscription + + // Add the uid to the notification document + notificationFields.uid = uid + + console.log(`Pushing notifications to users/${uid}/userNotificationFeed`) + + // Create a notification document in the user's notification feed + notificationPromises.push( + db + .collection(`users/${uid}/userNotificationFeed`) + .add(notificationFields) + ) }) } - else if (topic.type == "org") { - // console.log('org') - - // const handleOrgNotifications = async (topic: { court: any; id: string; name: string; history: string; lastUpdatedTime: any }) => { - // const notificationFields = createNotificationFields( - // topic, - // "org" - // ) - - // console.log(JSON.stringify(notificationFields)) - - // const subscriptionsSnapshot = await db - // .collectionGroup("activeTopicSubscriptions") - // .where("topicName", "==", notificationFields.topicName) - // .get() - - // subscriptionsSnapshot.docs.forEach(doc => { - // const subscription = doc.data() - // const { uid } = subscription - - // // Add the uid to the notification document - // notificationFields.uid = uid - - // console.log(`Pushing notifications to users/${uid}/userNotificationFeed`) - - // // Create a notification document in the user's notification feed - // notificationPromises.push( - // db - // .collection(`users/${uid}/userNotificationFeed`) - // .add(notificationFields) - // ) - // }) - // } - - // await handleOrgNotifications({ - // court: topic.court, - // id: topic.id, - // name: topic.name, - // history: JSON.stringify(topic.history), - // lastUpdatedTime: topic.historyUpdateTime - // }) - } + await handleNotifications(topic) // Wait for all notification documents to be created await Promise.all(notificationPromises) diff --git a/scripts/firebase-admin/seedNotificationEvents.ts b/scripts/firebase-admin/backfillBillNotificationEvents.ts similarity index 77% rename from scripts/firebase-admin/seedNotificationEvents.ts rename to scripts/firebase-admin/backfillBillNotificationEvents.ts index 72fc7cf95..6994fa8ca 100644 --- a/scripts/firebase-admin/seedNotificationEvents.ts +++ b/scripts/firebase-admin/backfillBillNotificationEvents.ts @@ -1,6 +1,6 @@ import { Timestamp } from "functions/src/firebase"; import { Script } from "./types"; -import { Notification } from "functions/src/notifications/populateNotificationEvents"; +import { Notification } from "functions/src/notifications/populateBillNotificationEvents"; import { Record, Number } from "runtypes"; const Args = Record({ @@ -25,11 +25,19 @@ export const script: Script = async ({ db, args }) => { if (data) { const notificationEvent: Notification = { type: "bill", - court: court, - id: data.id, - name: data.id, - history: data.history, - historyUpdateTime: Timestamp.now(), + + billCourt: court, + billId: data.id, + billName: data.id, + + billHistory: data.history, + + testimonyUser: "", + testimonyPosition: "", + testimonyContent: "", + testimonyVersion: -1, + + updateTime: Timestamp.now(), }; const ref = db.collection("/notificationEvents").doc(); From c4fc312f123731cd3172179328ff101ff4817e1c Mon Sep 17 00:00:00 2001 From: kiminkim724 Date: Tue, 27 Aug 2024 20:49:08 -0400 Subject: [PATCH 07/26] Fixed followButton on profile and hide button if not logged in --- components/ProfilePage/FollowButton.tsx | 22 +++++++------------- components/ProfilePage/ProfileButtons.tsx | 8 +++---- components/ProfilePage/ProfileHeader.tsx | 2 +- components/search/testimony/TestimonyHit.tsx | 4 +++- 4 files changed, 16 insertions(+), 20 deletions(-) diff --git a/components/ProfilePage/FollowButton.tsx b/components/ProfilePage/FollowButton.tsx index 80103275e..d03f0584a 100644 --- a/components/ProfilePage/FollowButton.tsx +++ b/components/ProfilePage/FollowButton.tsx @@ -5,19 +5,19 @@ import { Internal } from "components/links" import { StyledImage } from "./StyledProfileComponents" import { useTranslation } from "next-i18next" import { getFunctions, httpsCallable } from "firebase/functions" -import { useAuth } from "../auth" import { useState, useEffect, useCallback } from "react" import { FillButton } from "components/buttons" +import { User } from "firebase/auth" +import { Maybe } from "components/db/common" export const FollowButton = ({ profileId, - uid + user }: { - profileId?: string - uid?: string + profileId?: string, + user: Maybe }) => { const { t } = useTranslation("profile") - const { user } = useAuth() const functions = getFunctions() const followBillFunction = httpsCallable(functions, "followOrg") const unfollowBillFunction = httpsCallable(functions, "unfollowOrg") @@ -25,7 +25,7 @@ export const FollowButton = ({ const topicName = `org-${profileId}` const subscriptionRef = collection( firestore, - `/users/${uid}/activeTopicSubscriptions/` + `/users/${user?.uid}/activeTopicSubscriptions/` ) const [queryResult, setQueryResult] = useState("") @@ -42,8 +42,8 @@ export const FollowButton = ({ }, [subscriptionRef, profileId, setQueryResult]) // dependencies of orgQuery useEffect(() => { - uid ? orgQuery() : null - }, [uid, orgQuery]) // dependencies of useEffect + user?.uid ? orgQuery() : null + }, [user?.uid, orgQuery]) // dependencies of useEffect const handleFollowClick = async () => { // ensure user is not null @@ -52,9 +52,6 @@ export const FollowButton = ({ } try { - if (!uid) { - throw new Error("User not found") - } const orgLookup = { profileId: profileId, type: "org" @@ -76,9 +73,6 @@ export const FollowButton = ({ } try { - if (!uid) { - throw new Error("User not found") - } const orgLookup = { profileId: profileId, type: "org" diff --git a/components/ProfilePage/ProfileButtons.tsx b/components/ProfilePage/ProfileButtons.tsx index cd16f7d48..fddb461f8 100644 --- a/components/ProfilePage/ProfileButtons.tsx +++ b/components/ProfilePage/ProfileButtons.tsx @@ -3,12 +3,11 @@ import { useTranslation } from "next-i18next" import { Button } from "../bootstrap" import styled from "styled-components" import { FillButton, GearButton, ToggleButton } from "components/buttons" -import { Col } from "react-bootstrap" -import { Story } from "stories/atoms/BaseButton.stories" import { Internal } from "components/links" import { useProfile, ProfileHook } from "components/db" import { FollowButton } from "./FollowButton" import { useFlags } from "components/featureFlags" +import { useAuth } from "../auth" export const StyledButton = styled(Button).attrs(props => ({ className: `col-12 d-flex align-items-center justify-content-center py-3 text-nowrap`, @@ -90,9 +89,10 @@ export function ProfileButtonsUser({ ) } -export function ProfileButtonsOrg({ isUser }: { isUser: boolean }) { +export function ProfileButtonsOrg({ profileId, isUser }: { profileId: string, isUser: boolean }) { const { followOrg } = useFlags() + const { user } = useAuth() return ( - <>{isUser ? : followOrg ? : null} + <>{isUser ? : followOrg && user ? : null} ) } diff --git a/components/ProfilePage/ProfileHeader.tsx b/components/ProfilePage/ProfileHeader.tsx index 800ed72e3..8daf8cd61 100644 --- a/components/ProfilePage/ProfileHeader.tsx +++ b/components/ProfilePage/ProfileHeader.tsx @@ -34,7 +34,7 @@ export const ProfileHeader = ({ {profile.fullName} - {isOrg ? : null} + {isOrg ? : null}
diff --git a/components/search/testimony/TestimonyHit.tsx b/components/search/testimony/TestimonyHit.tsx index f161a5203..059939699 100644 --- a/components/search/testimony/TestimonyHit.tsx +++ b/components/search/testimony/TestimonyHit.tsx @@ -8,6 +8,7 @@ import { useBill } from "components/db/bills" import { FollowOrgButton } from "components/shared/FollowButton" import { Image } from "react-bootstrap" import { useFlags } from "components/featureFlags" +import { useAuth } from "components/auth" export const TestimonyHit = ({ hit }: { hit: Hit }) => { const url = maple.testimony({ publishedId: hit.id }) @@ -37,6 +38,7 @@ const TestimonyResult = ({ hit }: { hit: Hit }) => { ) : ( hit.authorDisplayName ) + const { user } = useAuth() const { followOrg } = useFlags() return ( @@ -65,7 +67,7 @@ const TestimonyResult = ({ hit }: { hit: Hit }) => { Written by {writtenBy} - {followOrg && isOrg && } + {followOrg && isOrg && user && }

From 5dcd067d82e7516eaf2ac82e3f6f886c56e1d5b5 Mon Sep 17 00:00:00 2001 From: kiminkim724 Date: Tue, 27 Aug 2024 20:56:28 -0400 Subject: [PATCH 08/26] Fixed prettier --- components/ProfilePage/FollowButton.tsx | 2 +- components/ProfilePage/ProfileButtons.tsx | 16 ++++++- components/ProfilePage/ProfileHeader.tsx | 4 +- components/search/testimony/TestimonyHit.tsx | 4 +- .../populateBillNotificationEvents.ts | 6 +-- .../populateOrgNotificationEvents.ts | 2 +- .../src/notifications/publishNotifications.ts | 8 ++-- .../backfillBillNotificationEvents.ts | 44 +++++++++---------- scripts/firebase-admin/generateBillHistory.ts | 4 +- 9 files changed, 54 insertions(+), 36 deletions(-) diff --git a/components/ProfilePage/FollowButton.tsx b/components/ProfilePage/FollowButton.tsx index d03f0584a..1be776db6 100644 --- a/components/ProfilePage/FollowButton.tsx +++ b/components/ProfilePage/FollowButton.tsx @@ -14,7 +14,7 @@ export const FollowButton = ({ profileId, user }: { - profileId?: string, + profileId?: string user: Maybe }) => { const { t } = useTranslation("profile") diff --git a/components/ProfilePage/ProfileButtons.tsx b/components/ProfilePage/ProfileButtons.tsx index fddb461f8..f95bc46c6 100644 --- a/components/ProfilePage/ProfileButtons.tsx +++ b/components/ProfilePage/ProfileButtons.tsx @@ -89,10 +89,22 @@ export function ProfileButtonsUser({ ) } -export function ProfileButtonsOrg({ profileId, isUser }: { profileId: string, isUser: boolean }) { +export function ProfileButtonsOrg({ + profileId, + isUser +}: { + profileId: string + isUser: boolean +}) { const { followOrg } = useFlags() const { user } = useAuth() return ( - <>{isUser ? : followOrg && user ? : null} + <> + {isUser ? ( + + ) : followOrg && user ? ( + + ) : null} + ) } diff --git a/components/ProfilePage/ProfileHeader.tsx b/components/ProfilePage/ProfileHeader.tsx index 8daf8cd61..1526d21dd 100644 --- a/components/ProfilePage/ProfileHeader.tsx +++ b/components/ProfilePage/ProfileHeader.tsx @@ -34,7 +34,9 @@ export const ProfileHeader = ({ {profile.fullName} - {isOrg ? : null} + {isOrg ? ( + + ) : null}
diff --git a/components/search/testimony/TestimonyHit.tsx b/components/search/testimony/TestimonyHit.tsx index 059939699..14d6feb47 100644 --- a/components/search/testimony/TestimonyHit.tsx +++ b/components/search/testimony/TestimonyHit.tsx @@ -67,7 +67,9 @@ const TestimonyResult = ({ hit }: { hit: Hit }) => { Written by {writtenBy} - {followOrg && isOrg && user && } + {followOrg && isOrg && user && ( + + )}

diff --git a/functions/src/notifications/populateBillNotificationEvents.ts b/functions/src/notifications/populateBillNotificationEvents.ts index adad4ca29..169e9f0ea 100644 --- a/functions/src/notifications/populateBillNotificationEvents.ts +++ b/functions/src/notifications/populateBillNotificationEvents.ts @@ -25,7 +25,7 @@ export type Notification = { testimonyPosition: string testimonyContent: string testimonyVersion: number - + updateTime: Timestamp } @@ -63,7 +63,7 @@ export const populateBillNotificationEvents = functions.firestore testimonyContent: "", testimonyVersion: -1, - updateTime: Timestamp.now(), + updateTime: Timestamp.now() } await db.collection("/notificationEvents").add(newNotificationEvent) @@ -100,7 +100,7 @@ export const populateBillNotificationEvents = functions.firestore .doc(notificationEventId) .update({ billHistory: newData?.history, - updateTime: Timestamp.now(), + updateTime: Timestamp.now() }) } } diff --git a/functions/src/notifications/populateOrgNotificationEvents.ts b/functions/src/notifications/populateOrgNotificationEvents.ts index caa559509..09f8659d8 100644 --- a/functions/src/notifications/populateOrgNotificationEvents.ts +++ b/functions/src/notifications/populateOrgNotificationEvents.ts @@ -84,7 +84,7 @@ export const populateOrgNotificationEvents = functions.firestore testimonyPosition: newData?.position, testimonyContent: newData?.content, testimonyVersion: newData?.version, - updateTime: Timestamp.now(), + updateTime: Timestamp.now() }) } } diff --git a/functions/src/notifications/publishNotifications.ts b/functions/src/notifications/publishNotifications.ts index 1e8272c2e..0d294204b 100644 --- a/functions/src/notifications/publishNotifications.ts +++ b/functions/src/notifications/publishNotifications.ts @@ -44,7 +44,7 @@ const createNotificationFields = (entity: Notification) => { console.log(`Invalid entity type: ${entity.type}`) throw new Error(`Invalid entity type: ${entity.type}`) } - + return { topicName, uid: "", @@ -57,7 +57,7 @@ const createNotificationFields = (entity: Notification) => { type: entity.type, court, delivered: false - }, + }, createdAt: Timestamp.now() } } @@ -95,7 +95,9 @@ export const publishNotifications = functions.firestore // Add the uid to the notification document notificationFields.uid = uid - console.log(`Pushing notifications to users/${uid}/userNotificationFeed`) + console.log( + `Pushing notifications to users/${uid}/userNotificationFeed` + ) // Create a notification document in the user's notification feed notificationPromises.push( diff --git a/scripts/firebase-admin/backfillBillNotificationEvents.ts b/scripts/firebase-admin/backfillBillNotificationEvents.ts index 6994fa8ca..d2dcaffa3 100644 --- a/scripts/firebase-admin/backfillBillNotificationEvents.ts +++ b/scripts/firebase-admin/backfillBillNotificationEvents.ts @@ -1,26 +1,26 @@ -import { Timestamp } from "functions/src/firebase"; -import { Script } from "./types"; -import { Notification } from "functions/src/notifications/populateBillNotificationEvents"; -import { Record, Number } from "runtypes"; +import { Timestamp } from "functions/src/firebase" +import { Script } from "./types" +import { Notification } from "functions/src/notifications/populateBillNotificationEvents" +import { Record, Number } from "runtypes" const Args = Record({ court: Number -}); +}) export const script: Script = async ({ db, args }) => { console.log(args) - const a = Args.check(args); - const court = a.court.toString(); + const a = Args.check(args) + const court = a.court.toString() - const snapshot = await db.collection(`/generalCourts/${court}/bills`).get(); + const snapshot = await db.collection(`/generalCourts/${court}/bills`).get() - const batchLimit = 500; - let batch = db.batch(); - let operationCount = 0; + const batchLimit = 500 + let batch = db.batch() + let operationCount = 0 for (const doc of snapshot.docs) { - const data = doc.data(); + const data = doc.data() if (data) { const notificationEvent: Notification = { @@ -37,22 +37,22 @@ export const script: Script = async ({ db, args }) => { testimonyContent: "", testimonyVersion: -1, - updateTime: Timestamp.now(), - }; + updateTime: Timestamp.now() + } - const ref = db.collection("/notificationEvents").doc(); - batch.set(ref, notificationEvent); - operationCount++; + const ref = db.collection("/notificationEvents").doc() + batch.set(ref, notificationEvent) + operationCount++ if (operationCount === batchLimit) { - await batch.commit(); - batch = db.batch(); - operationCount = 0; + await batch.commit() + batch = db.batch() + operationCount = 0 } } } if (operationCount > 0) { - await batch.commit(); + await batch.commit() } -}; +} diff --git a/scripts/firebase-admin/generateBillHistory.ts b/scripts/firebase-admin/generateBillHistory.ts index 4869a387d..6bc4ffaea 100644 --- a/scripts/firebase-admin/generateBillHistory.ts +++ b/scripts/firebase-admin/generateBillHistory.ts @@ -18,7 +18,7 @@ export const script: Script = async ({ db, args }) => { for (const id of bills) { const billHistoryAction: BillHistoryAction = { Date: Timestamp.now().valueOf(), - Branch: Math.random() < 0.5 ? 'Senate' : 'House', + Branch: Math.random() < 0.5 ? "Senate" : "House", Action: (Math.random() + 1).toString(36).substring(2) } @@ -37,4 +37,4 @@ export const script: Script = async ({ db, args }) => { } console.log(`Batch of ${opsCounter} bills updated.`) -} \ No newline at end of file +} From bfac23deb3d9ebd455713d691c323ec00c1be399 Mon Sep 17 00:00:00 2001 From: Merritt Baggett Date: Wed, 4 Sep 2024 13:42:25 -0400 Subject: [PATCH 09/26] Partners in Democracy --- components/OurTeam/Partners.tsx | 17 ++++++++++------- public/locales/en/common.json | 7 +++++++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/components/OurTeam/Partners.tsx b/components/OurTeam/Partners.tsx index 4830c1baa..0a964f081 100644 --- a/components/OurTeam/Partners.tsx +++ b/components/OurTeam/Partners.tsx @@ -8,33 +8,36 @@ import { } from "../OurPartnersCardContent/OurPartnersCardContent" import { PageTitle, PageDescr } from "./CommonComponents" +import { useTranslation } from "next-i18next" + export const OurPartners = () => { + const { t } = useTranslation("common") + return ( - Our Partners + {t("partners.header")} - The project is developed in partnership between the NuLawLab and - scholars at{" "} + {t("partners.desc1")}{" "} - Boston College Law School + {t("partners.desc2")} {" "} - and{" "} + {t("partners.desc3")}{" "} - Harvard University's Berkman Klein Center for Internet & Society + {t("partners.desc4")} . @@ -56,7 +59,7 @@ export const OurPartners = () => { - + diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 16aa31a58..5d2e17447 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -45,6 +45,13 @@ "newcomer" : "New to MAPLE? For extra support, check", "notInCommittee": "Bill not currently in committee", "orgs": "Organizations", + "partners": { + "header": "Our Partners", + "desc1": "The project is developed in partnership between the NuLawLab and scholars at", + "desc2": "Boston College Law School", + "desc3": "and", + "desc4": "Harvard University's Berkman Klein Center for Internet & Society" + }, "pending_upgrade_warning": { "header": "Organization Request In Progress", "content": "Your request to be upgraded to an organization is currently in progress. You will be notified by email when your request has been reviewed." From 5fd06e1b32e1c329af21106b0accbba7b31c7df9 Mon Sep 17 00:00:00 2001 From: Merritt Baggett Date: Wed, 4 Sep 2024 13:55:54 -0400 Subject: [PATCH 10/26] linter does not like literal strings --- components/OurTeam/Partners.tsx | 16 +++++++++++++--- public/locales/en/common.json | 7 +++---- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/components/OurTeam/Partners.tsx b/components/OurTeam/Partners.tsx index 0a964f081..e757fce0f 100644 --- a/components/OurTeam/Partners.tsx +++ b/components/OurTeam/Partners.tsx @@ -13,6 +13,14 @@ import { useTranslation } from "next-i18next" export const OurPartners = () => { const { t } = useTranslation("common") + { + /*linter does not like literal strings */ + } + const untranslatedProperTitle1 = "NuLawLab" + const untranslatedProperTitle2 = "Boston College Law School" + const untranslatedProperTitle3 = + "Harvard University's Berkman Klein Center for Internet & Society" + return ( @@ -23,13 +31,15 @@ export const OurPartners = () => { - {t("partners.desc1")}{" "} + {t("partners.desc1")} {untranslatedProperTitle1}{" "} + {t("partners.desc2")} - {t("partners.desc2")} + {" "} + {untranslatedProperTitle2} {" "} {t("partners.desc3")}{" "} { target="_blank" rel="noopener noreferrer" > - {t("partners.desc4")} + {untranslatedProperTitle3} . diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 5d2e17447..78011dfb8 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -47,10 +47,9 @@ "orgs": "Organizations", "partners": { "header": "Our Partners", - "desc1": "The project is developed in partnership between the NuLawLab and scholars at", - "desc2": "Boston College Law School", - "desc3": "and", - "desc4": "Harvard University's Berkman Klein Center for Internet & Society" + "desc1": "The project is developed in partnership between the", + "desc2": "and scholars at", + "desc3": "and" }, "pending_upgrade_warning": { "header": "Organization Request In Progress", From ac59c371d93e20e3579b4fe43d48c6ce1658bb09 Mon Sep 17 00:00:00 2001 From: Merritt Baggett Date: Wed, 4 Sep 2024 17:09:28 -0400 Subject: [PATCH 11/26] update logo for partners in democracy --- .../OurPartnersCardContent.tsx | 16 ++++++---------- components/OurTeam/Partners.tsx | 3 +-- public/locales/en/common.json | 3 ++- public/pid.png | Bin 0 -> 8263 bytes 4 files changed, 9 insertions(+), 13 deletions(-) create mode 100644 public/pid.png diff --git a/components/OurPartnersCardContent/OurPartnersCardContent.tsx b/components/OurPartnersCardContent/OurPartnersCardContent.tsx index 813a8833e..77a27170c 100644 --- a/components/OurPartnersCardContent/OurPartnersCardContent.tsx +++ b/components/OurPartnersCardContent/OurPartnersCardContent.tsx @@ -1,5 +1,6 @@ -import { Row, Col } from "../bootstrap" +import { useTranslation } from "next-i18next" import Image from "react-bootstrap/Image" +import { Row, Col } from "../bootstrap" const NuLawLabCardContent = () => { return ( @@ -93,22 +94,17 @@ const CodeForBostonCardContent = () => { } const OpenCollectiveContent = () => { + const { t } = useTranslation("common") + return ( <> - open_collective_logo + partners in democracy logo

- MAPLE is a fiscally sponsored initiative of the 501(c)(3), the Open - Collective Foundation (OCF). You can see a full list of our donors - and expenditures on our Open Collective webpage. You can also join - the list and make a donation through the sit. + {t("partners.pid")}

diff --git a/components/OurTeam/Partners.tsx b/components/OurTeam/Partners.tsx index e757fce0f..ab56aecd8 100644 --- a/components/OurTeam/Partners.tsx +++ b/components/OurTeam/Partners.tsx @@ -1,3 +1,4 @@ +import { useTranslation } from "next-i18next" import styled from "styled-components" import AboutPagesCard from "../AboutPagesCard/AboutPagesCard" import { Col, Container, Row } from "../bootstrap" @@ -8,8 +9,6 @@ import { } from "../OurPartnersCardContent/OurPartnersCardContent" import { PageTitle, PageDescr } from "./CommonComponents" -import { useTranslation } from "next-i18next" - export const OurPartners = () => { const { t } = useTranslation("common") diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 78011dfb8..bc1272860 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -49,7 +49,8 @@ "header": "Our Partners", "desc1": "The project is developed in partnership between the", "desc2": "and scholars at", - "desc3": "and" + "desc3": "and", + "pid": "MAPLE is an initiative of Partners in Democracy - Education, a 501(c)(3) non profit organization. Partners In Democracy is building nationwide partnerships and exploring how we can drive democracy renovation efforts forward in states around the country — starting by focusing our efforts here at home in Massachusetts." }, "pending_upgrade_warning": { "header": "Organization Request In Progress", diff --git a/public/pid.png b/public/pid.png new file mode 100644 index 0000000000000000000000000000000000000000..7187bcab487dc0b676e012f2e01dd20928e6f843 GIT binary patch literal 8263 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 literal 0 HcmV?d00001 From 03297dbd9583f6e23a261a1f8cf5b351d2b79dd7 Mon Sep 17 00:00:00 2001 From: Merritt Baggett Date: Wed, 4 Sep 2024 17:26:38 -0400 Subject: [PATCH 12/26] faq --- components/Faq/faqContent.json | 6 +++--- .../SupportMapleCardContent/SupportMapleCardContent.tsx | 3 +-- public/locales/en/supportmaple.json | 5 ++--- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/components/Faq/faqContent.json b/components/Faq/faqContent.json index 787f15f43..d8e9aa5bd 100755 --- a/components/Faq/faqContent.json +++ b/components/Faq/faqContent.json @@ -103,15 +103,15 @@ "qAndA": [ { "question": "Who is behind MAPLE?", - "answer": "We are a collective of open source developers, legal scholars, and policy analysts & advocates seeking to leverage digital technology to improve our capacity and ability to self-govern. The MAPLE platform is a project of the NuLawLab of Northeastern University developed with Code for Boston. We are volunteer-led and operate as a nonprofit project of the 501c3 organization OpenCollective Foundation." + "answer": "We are a collective of open source developers, legal scholars, and policy analysts & advocates seeking to leverage digital technology to improve our capacity and ability to self-govern. The MAPLE platform is a project of the NuLawLab of Northeastern University developed with Code for Boston. We are volunteer-led and operate as an initiative for Partners In Democracy - Education, a 501(c)(3) organization." }, { "question": "How can I support MAPLE?", - "answer": "There are lots of ways to support MAPLE! Please visit this page for details on how to help MAPLE grow, share feedback, volunteer with us, or even contribute financially." + "answer": "There are lots of ways to support MAPLE! For details on how to help MAPLE grow, share feedback, volunteer with us, or even contribute financially, please visit this page: https://www.mapletestimony.org/about/support-maple" }, { "question": "Who do I contact to learn more?", - "answer": "You can reach our volunteer leadership by email at info@mapletestimony.org." + "answer": "You can reach our volunteer leadership by email at admin@mapletestimony.org." } ] } diff --git a/components/about/SupportMapleCardContent/SupportMapleCardContent.tsx b/components/about/SupportMapleCardContent/SupportMapleCardContent.tsx index b4a858b7e..5ededa723 100644 --- a/components/about/SupportMapleCardContent/SupportMapleCardContent.tsx +++ b/components/about/SupportMapleCardContent/SupportMapleCardContent.tsx @@ -7,13 +7,12 @@ const DonateCardContent = () => {

{`${t("donate.bodytextOne")} `} {t("donate.donorsLink")} - {` ${t("donate.bodytextTwo")}`}

) diff --git a/public/locales/en/supportmaple.json b/public/locales/en/supportmaple.json index c37e84764..c8fd6d5fa 100644 --- a/public/locales/en/supportmaple.json +++ b/public/locales/en/supportmaple.json @@ -2,9 +2,8 @@ "title": "How to Support MAPLE", "donate": { "header": "Donate", - "bodytextOne": "MAPLE is a fiscally sponsored initiative of the 501(c)(3), the Open Collective Foundation (OCF).", - "donorsLink": "You can see a full list of our donors and expenditures on our Open Collective webpage.", - "bodytextTwo": "This is where you can view the details of every donation we've received and every dollar we've spent - we are 100% transparent. We would be grateful for your financial support. " + "bodytextOne": "MAPLE is an initiative of Partners in Democracy - Education, a 501(c)(3) non profit organization. You can donate directly to the development of MAPLE through this ", + "donorsLink": "link" }, "volunteer": { "header": "Volunteer", From 45a3a61ef26fbc400a207feeab522cfd33fe82af Mon Sep 17 00:00:00 2001 From: Merritt Baggett Date: Wed, 4 Sep 2024 17:28:52 -0400 Subject: [PATCH 13/26] clean up --- components/OurTeam/Partners.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/components/OurTeam/Partners.tsx b/components/OurTeam/Partners.tsx index ab56aecd8..93da87204 100644 --- a/components/OurTeam/Partners.tsx +++ b/components/OurTeam/Partners.tsx @@ -12,9 +12,8 @@ import { PageTitle, PageDescr } from "./CommonComponents" export const OurPartners = () => { const { t } = useTranslation("common") - { - /*linter does not like literal strings */ - } + // linter does not like literal strings + const untranslatedProperTitle1 = "NuLawLab" const untranslatedProperTitle2 = "Boston College Law School" const untranslatedProperTitle3 = From f766b36a40976babe391eb7a33f19b5ea20b1d92 Mon Sep 17 00:00:00 2001 From: kiminkim724 Date: Sun, 8 Sep 2024 11:34:59 -0400 Subject: [PATCH 14/26] Updates types and field names --- .../populateBillNotificationEvents.ts | 28 ++----------------- .../populateOrgNotificationEvents.ts | 12 ++++---- .../src/notifications/publishNotifications.ts | 21 +++++++++----- functions/src/notifications/types.ts | 24 ++++++++++++++++ .../backfillBillNotificationEvents.ts | 11 ++------ 5 files changed, 50 insertions(+), 46 deletions(-) create mode 100644 functions/src/notifications/types.ts diff --git a/functions/src/notifications/populateBillNotificationEvents.ts b/functions/src/notifications/populateBillNotificationEvents.ts index 169e9f0ea..da6bff519 100644 --- a/functions/src/notifications/populateBillNotificationEvents.ts +++ b/functions/src/notifications/populateBillNotificationEvents.ts @@ -7,28 +7,11 @@ import * as functions from "firebase-functions" import * as admin from "firebase-admin" import { Timestamp } from "../firebase" -import { BillHistory } from "../bills/types" +import { BillNotification } from "./types" // Get a reference to the Firestore database const db = admin.firestore() -export type Notification = { - type: string - - billCourt: string - billId: string - billName: string - - billHistory: BillHistory - - testimonyUser: string - testimonyPosition: string - testimonyContent: string - testimonyVersion: number - - updateTime: Timestamp -} - // Define the populateBillNotificationEvents function export const populateBillNotificationEvents = functions.firestore .document("/generalCourts/{court}/bills/{billId}") @@ -49,20 +32,15 @@ export const populateBillNotificationEvents = functions.firestore if (documentCreated) { console.log("New document created") - const newNotificationEvent: Notification = { + const newNotificationEvent: BillNotification = { type: "bill", billCourt: court, billId: newData?.id, - billName: newData?.id, + billName: newData?.content.Title, billHistory: newData?.history, - testimonyUser: "", - testimonyPosition: "", - testimonyContent: "", - testimonyVersion: -1, - updateTime: Timestamp.now() } diff --git a/functions/src/notifications/populateOrgNotificationEvents.ts b/functions/src/notifications/populateOrgNotificationEvents.ts index 09f8659d8..c4879d5aa 100644 --- a/functions/src/notifications/populateOrgNotificationEvents.ts +++ b/functions/src/notifications/populateOrgNotificationEvents.ts @@ -7,7 +7,7 @@ import * as functions from "firebase-functions" import * as admin from "firebase-admin" import { Timestamp } from "../firebase" -import { Notification } from "./populateBillNotificationEvents" +import { OrgNotification } from "./types" // Get a reference to the Firestore database const db = admin.firestore() @@ -25,20 +25,20 @@ export const populateOrgNotificationEvents = functions.firestore const oldData = snapshot.before.data() const newData = snapshot.after.data() + console.log(newData) // New testimony added if (documentCreated) { console.log("New document created") - const newNotificationEvent: Notification = { + const newNotificationEvent: OrgNotification = { type: "org", billCourt: newData?.court.toString(), billId: newData?.id, - billName: newData?.id, - - billHistory: [], + billName: newData?.billTitle, + orgId: newData?.authorUid, testimonyUser: newData?.fullName, testimonyPosition: newData?.position, testimonyContent: newData?.content, @@ -63,7 +63,7 @@ export const populateOrgNotificationEvents = functions.firestore .where("type", "==", "org") .where("billCourt", "==", newData?.court.toString()) .where("billId", "==", newData?.id) - .where("fullName", "==", newData?.fullName) + .where("authorUid", "==", newData?.authorUid) .get() console.log( diff --git a/functions/src/notifications/publishNotifications.ts b/functions/src/notifications/publishNotifications.ts index 0d294204b..2e423f5e3 100644 --- a/functions/src/notifications/publishNotifications.ts +++ b/functions/src/notifications/publishNotifications.ts @@ -7,12 +7,14 @@ import * as functions from "firebase-functions" import * as admin from "firebase-admin" import { Timestamp } from "../firebase" -import { Notification } from "./populateBillNotificationEvents" +import { BillNotification, OrgNotification } from "./types" // Get a reference to the Firestore database const db = admin.firestore() -const createNotificationFields = (entity: Notification) => { +const createNotificationFields = ( + entity: BillNotification | OrgNotification +) => { let topicName: string let header: string let court: string | null = null @@ -34,15 +36,15 @@ const createNotificationFields = (entity: Notification) => { break case "org": - topicName = `org-${entity.testimonyUser}` + topicName = `org-${entity.orgId}` header = entity.billName bodyText = entity.testimonyContent subheader = entity.testimonyUser break default: - console.log(`Invalid entity type: ${entity.type}`) - throw new Error(`Invalid entity type: ${entity.type}`) + console.log(`Invalid entity: ${entity}`) + throw new Error(`Invalid entity: ${entity}`) } return { @@ -67,7 +69,10 @@ export const publishNotifications = functions.firestore .document("/notificationEvents/{topicEventId}") .onWrite(async (snapshot, context) => { // Get the newly created topic event data - const topic = snapshot?.after.data() as Notification | undefined + const topic = snapshot?.after.data() as + | BillNotification + | OrgNotification + | undefined if (!topic) { console.error("Invalid topic data:", topic) @@ -78,7 +83,9 @@ export const publishNotifications = functions.firestore const notificationPromises: any[] = [] console.log(`topic type: ${topic.type}`) - const handleNotifications = async (topic: Notification) => { + const handleNotifications = async ( + topic: BillNotification | OrgNotification + ) => { const notificationFields = createNotificationFields(topic) console.log(JSON.stringify(notificationFields)) diff --git a/functions/src/notifications/types.ts b/functions/src/notifications/types.ts new file mode 100644 index 000000000..35144f003 --- /dev/null +++ b/functions/src/notifications/types.ts @@ -0,0 +1,24 @@ +import { BillHistory } from "../bills/types" +import { Timestamp } from "../firebase" + +export interface Notification { + type: string + updateTime: Timestamp + billCourt: string + billId: string + billName: string +} + +export type BillNotification = Notification & { + type: "bill" + billHistory: BillHistory +} + +export type OrgNotification = Notification & { + type: "org" + orgId: string + testimonyUser: string + testimonyPosition: string + testimonyContent: string + testimonyVersion: number +} diff --git a/scripts/firebase-admin/backfillBillNotificationEvents.ts b/scripts/firebase-admin/backfillBillNotificationEvents.ts index d2dcaffa3..db44e498d 100644 --- a/scripts/firebase-admin/backfillBillNotificationEvents.ts +++ b/scripts/firebase-admin/backfillBillNotificationEvents.ts @@ -1,6 +1,6 @@ import { Timestamp } from "functions/src/firebase" import { Script } from "./types" -import { Notification } from "functions/src/notifications/populateBillNotificationEvents" +import { BillNotification } from "functions/src/notifications/types" import { Record, Number } from "runtypes" const Args = Record({ @@ -23,20 +23,15 @@ export const script: Script = async ({ db, args }) => { const data = doc.data() if (data) { - const notificationEvent: Notification = { + const notificationEvent: BillNotification = { type: "bill", billCourt: court, billId: data.id, - billName: data.id, + billName: data?.content.Title, billHistory: data.history, - testimonyUser: "", - testimonyPosition: "", - testimonyContent: "", - testimonyVersion: -1, - updateTime: Timestamp.now() } From b2bb09ad671dae9bc26a6a8ac8190d9066c19cdf Mon Sep 17 00:00:00 2001 From: kiminkim724 Date: Sun, 8 Sep 2024 11:54:53 -0400 Subject: [PATCH 15/26] Remove console.log --- functions/src/notifications/populateOrgNotificationEvents.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/functions/src/notifications/populateOrgNotificationEvents.ts b/functions/src/notifications/populateOrgNotificationEvents.ts index c4879d5aa..7e04f4371 100644 --- a/functions/src/notifications/populateOrgNotificationEvents.ts +++ b/functions/src/notifications/populateOrgNotificationEvents.ts @@ -12,7 +12,7 @@ import { OrgNotification } from "./types" // Get a reference to the Firestore database const db = admin.firestore() -// Define the populateBillNotificationEvents function +// Define the populateOrgNotificationEvents function export const populateOrgNotificationEvents = functions.firestore .document("/users/{userId}/publishedTestimony/{testimonyId}") .onWrite(async (snapshot, context) => { @@ -25,7 +25,6 @@ export const populateOrgNotificationEvents = functions.firestore const oldData = snapshot.before.data() const newData = snapshot.after.data() - console.log(newData) // New testimony added if (documentCreated) { From bb16e947c10b5cf9252a8941081a5677974e241e Mon Sep 17 00:00:00 2001 From: Merritt Baggett Date: Sun, 8 Sep 2024 12:46:39 -0400 Subject: [PATCH 16/26] changed Volunteer link --- .../about/SupportMapleCardContent/SupportMapleCardContent.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/about/SupportMapleCardContent/SupportMapleCardContent.tsx b/components/about/SupportMapleCardContent/SupportMapleCardContent.tsx index 5ededa723..8181c9d4a 100644 --- a/components/about/SupportMapleCardContent/SupportMapleCardContent.tsx +++ b/components/about/SupportMapleCardContent/SupportMapleCardContent.tsx @@ -32,7 +32,7 @@ const VolunteerCardContent = () => { {t("volunteer.githubLink")} {`, ${t("volunteer.bodytextTwo")} `} - info@mapletestimony.org. + admin@mapletestimony.org.

) From 626a8b071c6f782253e89747555f24b6469d8c04 Mon Sep 17 00:00:00 2001 From: kiminkim724 Date: Sun, 8 Sep 2024 13:02:48 -0400 Subject: [PATCH 17/26] Added notification for new testimony on bills --- .../populateOrgNotificationEvents.ts | 4 ++-- .../src/notifications/publishNotifications.ts | 24 +++++++++++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/functions/src/notifications/populateOrgNotificationEvents.ts b/functions/src/notifications/populateOrgNotificationEvents.ts index 7e04f4371..ee3e5465b 100644 --- a/functions/src/notifications/populateOrgNotificationEvents.ts +++ b/functions/src/notifications/populateOrgNotificationEvents.ts @@ -34,7 +34,7 @@ export const populateOrgNotificationEvents = functions.firestore type: "org", billCourt: newData?.court.toString(), - billId: newData?.id, + billId: newData?.billId, billName: newData?.billTitle, orgId: newData?.authorUid, @@ -61,7 +61,7 @@ export const populateOrgNotificationEvents = functions.firestore .collection("/notificationEvents") .where("type", "==", "org") .where("billCourt", "==", newData?.court.toString()) - .where("billId", "==", newData?.id) + .where("billId", "==", newData?.billId) .where("authorUid", "==", newData?.authorUid) .get() diff --git a/functions/src/notifications/publishNotifications.ts b/functions/src/notifications/publishNotifications.ts index 2e423f5e3..08ee6c4ad 100644 --- a/functions/src/notifications/publishNotifications.ts +++ b/functions/src/notifications/publishNotifications.ts @@ -38,6 +38,7 @@ const createNotificationFields = ( case "org": topicName = `org-${entity.orgId}` header = entity.billName + court = entity.billCourt bodyText = entity.testimonyContent subheader = entity.testimonyUser break @@ -90,12 +91,31 @@ export const publishNotifications = functions.firestore console.log(JSON.stringify(notificationFields)) - const subscriptionsSnapshot = await db + const topicNameSnapshot = await db .collectionGroup("activeTopicSubscriptions") .where("topicName", "==", notificationFields.topicName) .get() - subscriptionsSnapshot.docs.forEach(doc => { + // Send a testimony notification to all users subscribed to the Bill + let billSnapshot + if (notificationFields.notification.type !== "bill") { + billSnapshot = await db + .collectionGroup("activeTopicSubscriptions") + .where( + "topicName", + "==", + `bill-${notificationFields.notification.court}-${notificationFields.notification.id}` + ) + .get() + } + + // Merge the snapshots + const subscriptionsSnapshot = [ + ...topicNameSnapshot.docs, + ...(billSnapshot?.docs ?? []) + ] + + subscriptionsSnapshot.forEach(doc => { const subscription = doc.data() const { uid } = subscription From dc1051f340854da50d82820e284c459f2e73149b Mon Sep 17 00:00:00 2001 From: Merritt Baggett Date: Sun, 8 Sep 2024 21:09:10 -0400 Subject: [PATCH 18/26] support link --- components/Faq/FaqQandAButton.tsx | 8 ++++++++ components/Faq/faqContent.json | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/components/Faq/FaqQandAButton.tsx b/components/Faq/FaqQandAButton.tsx index ce2f463c3..65c4c5ff9 100644 --- a/components/Faq/FaqQandAButton.tsx +++ b/components/Faq/FaqQandAButton.tsx @@ -11,6 +11,8 @@ export const FaqQandAButton = ({ question, answer }: faqQandAProps) => { useEffect(() => {}, [open]) + const supportLink = "this page" + return ( <> {

{answer} + {question == "How can I support MAPLE?" ? ( + + {" "} + {supportLink} + + ) : null}

diff --git a/components/Faq/faqContent.json b/components/Faq/faqContent.json index d8e9aa5bd..da2ca0458 100755 --- a/components/Faq/faqContent.json +++ b/components/Faq/faqContent.json @@ -107,7 +107,7 @@ }, { "question": "How can I support MAPLE?", - "answer": "There are lots of ways to support MAPLE! For details on how to help MAPLE grow, share feedback, volunteer with us, or even contribute financially, please visit this page: https://www.mapletestimony.org/about/support-maple" + "answer": "There are lots of ways to support MAPLE! For details on how to help MAPLE grow, share feedback, volunteer with us, or even contribute financially, please visit " }, { "question": "Who do I contact to learn more?", From b2791a3a8485e265fd8164fc51ab5c5f0437055a Mon Sep 17 00:00:00 2001 From: Merritt Baggett Date: Sun, 8 Sep 2024 21:20:52 -0400 Subject: [PATCH 19/26] simplified partner code --- components/OurTeam/Partners.tsx | 25 +++++++++++++------------ public/locales/en/common.json | 7 +++++-- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/components/OurTeam/Partners.tsx b/components/OurTeam/Partners.tsx index 93da87204..385ca822f 100644 --- a/components/OurTeam/Partners.tsx +++ b/components/OurTeam/Partners.tsx @@ -12,13 +12,6 @@ import { PageTitle, PageDescr } from "./CommonComponents" export const OurPartners = () => { const { t } = useTranslation("common") - // linter does not like literal strings - - const untranslatedProperTitle1 = "NuLawLab" - const untranslatedProperTitle2 = "Boston College Law School" - const untranslatedProperTitle3 = - "Harvard University's Berkman Klein Center for Internet & Society" - return ( @@ -29,23 +22,31 @@ export const OurPartners = () => { - {t("partners.desc1")} {untranslatedProperTitle1}{" "} - {t("partners.desc2")} + {t("partners.desc1")} + + {" "} + {t("partners.desc2")} + {" "} + {t("partners.desc3")} {" "} - {untranslatedProperTitle2} + {t("partners.desc4")} {" "} - {t("partners.desc3")}{" "} + {t("partners.desc5")}{" "} - {untranslatedProperTitle3} + {t("partners.desc6")} . diff --git a/public/locales/en/common.json b/public/locales/en/common.json index bc1272860..c138f9c7f 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -48,8 +48,11 @@ "partners": { "header": "Our Partners", "desc1": "The project is developed in partnership between the", - "desc2": "and scholars at", - "desc3": "and", + "desc2": "NuLawLab", + "desc3": "and scholars at", + "desc4": "Boston College Law School", + "desc5": "and", + "desc6": "Harvard University's Berkman Klein Center for Internet & Society", "pid": "MAPLE is an initiative of Partners in Democracy - Education, a 501(c)(3) non profit organization. Partners In Democracy is building nationwide partnerships and exploring how we can drive democracy renovation efforts forward in states around the country — starting by focusing our efforts here at home in Massachusetts." }, "pending_upgrade_warning": { From 08ad87fe8cd8d0ea479ba13f96d027139bde210e Mon Sep 17 00:00:00 2001 From: Merritt Baggett Date: Sun, 8 Sep 2024 21:45:02 -0400 Subject: [PATCH 20/26] slight refactor --- components/Faq/FaqQandAButton.tsx | 19 ++++++++++++------- .../SupportMapleCardContent.tsx | 4 +++- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/components/Faq/FaqQandAButton.tsx b/components/Faq/FaqQandAButton.tsx index 65c4c5ff9..28f944cdc 100644 --- a/components/Faq/FaqQandAButton.tsx +++ b/components/Faq/FaqQandAButton.tsx @@ -11,7 +11,17 @@ export const FaqQandAButton = ({ question, answer }: faqQandAProps) => { useEffect(() => {}, [open]) - const supportLink = "this page" + let supportLink = null + + { + question == "How can I support MAPLE?" + ? (supportLink = ( + + {" this page"} + + )) + : null + } return ( <> @@ -32,12 +42,7 @@ export const FaqQandAButton = ({ question, answer }: faqQandAProps) => {

{answer} - {question == "How can I support MAPLE?" ? ( - - {" "} - {supportLink} - - ) : null} + {supportLink}

diff --git a/components/about/SupportMapleCardContent/SupportMapleCardContent.tsx b/components/about/SupportMapleCardContent/SupportMapleCardContent.tsx index 8181c9d4a..2139cf9aa 100644 --- a/components/about/SupportMapleCardContent/SupportMapleCardContent.tsx +++ b/components/about/SupportMapleCardContent/SupportMapleCardContent.tsx @@ -32,7 +32,9 @@ const VolunteerCardContent = () => { {t("volunteer.githubLink")} {`, ${t("volunteer.bodytextTwo")} `} - admin@mapletestimony.org. + + {"admin@mapletestimony.org."} +

) From 5d29ddb6fc29ba1b08ab37c17c9c487a5dc3d931 Mon Sep 17 00:00:00 2001 From: kiminkim724 Date: Tue, 10 Sep 2024 19:40:01 -0400 Subject: [PATCH 21/26] Remove duplicates --- .../src/notifications/publishNotifications.ts | 41 ++++++++++++------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/functions/src/notifications/publishNotifications.ts b/functions/src/notifications/publishNotifications.ts index 08ee6c4ad..3afc12812 100644 --- a/functions/src/notifications/publishNotifications.ts +++ b/functions/src/notifications/publishNotifications.ts @@ -82,6 +82,9 @@ export const publishNotifications = functions.firestore // Extract related Bill or Org data from the topic event const notificationPromises: any[] = [] + + // Create a batch + const batch = db.batch() console.log(`topic type: ${topic.type}`) const handleNotifications = async ( @@ -109,14 +112,24 @@ export const publishNotifications = functions.firestore .get() } - // Merge the snapshots - const subscriptionsSnapshot = [ - ...topicNameSnapshot.docs, - ...(billSnapshot?.docs ?? []) - ] + const uniqueDocs = new Map() + + // Add documents from topicNameSnapshot to the Map + topicNameSnapshot.docs.forEach(doc => { + uniqueDocs.set(doc.data().uid, doc.data()) + }) + + // If billSnapshot exists, add its documents to the Map + if (billSnapshot) { + billSnapshot.docs.forEach(doc => { + uniqueDocs.set(doc.data().uid, doc.data()) + }) + } + + // Convert the Map values to an array to get the unique documents + const subscriptionsSnapshot = Array.from(uniqueDocs.values()) - subscriptionsSnapshot.forEach(doc => { - const subscription = doc.data() + subscriptionsSnapshot.forEach(subscription => { const { uid } = subscription // Add the uid to the notification document @@ -126,17 +139,15 @@ export const publishNotifications = functions.firestore `Pushing notifications to users/${uid}/userNotificationFeed` ) - // Create a notification document in the user's notification feed - notificationPromises.push( - db - .collection(`users/${uid}/userNotificationFeed`) - .add(notificationFields) - ) + // Get a reference to the new notification document + const docRef = db.collection(`users/${uid}/userNotificationFeed`).doc() + + // Add the write operation to the batch + batch.set(docRef, notificationFields) }) } await handleNotifications(topic) - // Wait for all notification documents to be created - await Promise.all(notificationPromises) + notificationPromises.push(batch.commit()) }) From 98636f335ab088da91f1996414fc5ca947b59bb2 Mon Sep 17 00:00:00 2001 From: LauraUmana <11620537+LauraUmana@users.noreply.github.com> Date: Tue, 10 Sep 2024 19:50:25 -0400 Subject: [PATCH 22/26] made footer and browse bills copy changes --- pages/bills/index.tsx | 2 +- public/locales/en/footer.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pages/bills/index.tsx b/pages/bills/index.tsx index b82b64d99..45507492a 100644 --- a/pages/bills/index.tsx +++ b/pages/bills/index.tsx @@ -8,7 +8,7 @@ export default createPage({ Page: () => { return ( -

All Bills

+

Browse Bills

) diff --git a/public/locales/en/footer.json b/public/locales/en/footer.json index 0070a42f3..58b211286 100644 --- a/public/locales/en/footer.json +++ b/public/locales/en/footer.json @@ -6,9 +6,9 @@ "resources": "Resources" }, "links": { - "learnWriting": "To Writing Effective Testimony", + "learnWriting": "To Write Effective Testimony", "learnProcess": "About the Legislative Process", - "learnWhy": "Why use MAPLE", + "learnWhy": "Why Use MAPLE", "supportMaple": "Support MAPLE", "ourMission": "Mission & Goals", "team": "Team", From 253c148c220fc71837e3914d28b4128c003adace Mon Sep 17 00:00:00 2001 From: LauraUmana <11620537+LauraUmana@users.noreply.github.com> Date: Tue, 10 Sep 2024 20:19:14 -0400 Subject: [PATCH 23/26] deleted "1 2 3" component and removed text in mission and goals --- .../GoalsAndMissionCardContent.tsx | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/components/GoalsAndMissionCardContent/GoalsAndMissionCardContent.tsx b/components/GoalsAndMissionCardContent/GoalsAndMissionCardContent.tsx index 1192b2b7f..5be83185b 100644 --- a/components/GoalsAndMissionCardContent/GoalsAndMissionCardContent.tsx +++ b/components/GoalsAndMissionCardContent/GoalsAndMissionCardContent.tsx @@ -138,7 +138,6 @@ const OurMissionCardContent = () => { -

{t("mission.callout")}

@@ -156,29 +155,6 @@ const OurMissionCardContent = () => { - - - - - - - - - - - {!authenticated && ( <> From bda06946151e2386ae04dbe5b623af33e51747fe Mon Sep 17 00:00:00 2001 From: LauraUmana <11620537+LauraUmana@users.noreply.github.com> Date: Tue, 10 Sep 2024 20:45:43 -0400 Subject: [PATCH 24/26] updated Steering Committee page --- components/OurTeam/SteeringCommittee.tsx | 35 +++++++++++++++++++----- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/components/OurTeam/SteeringCommittee.tsx b/components/OurTeam/SteeringCommittee.tsx index b5fa5aa39..8d90578f5 100644 --- a/components/OurTeam/SteeringCommittee.tsx +++ b/components/OurTeam/SteeringCommittee.tsx @@ -53,6 +53,16 @@ export const SteeringCommittee = () => { name="Dan Jackson" descr="Dan Jackson directs Northeastern University School of Law’s NuLawLab, where he draws on his design and law backgrounds to educate the legal inventors of the future." /> + + + + @@ -60,22 +70,33 @@ export const SteeringCommittee = () => { - User Experience Design & Engineering Leads + User Experience, Design & Engineering Leads + + + + +
From 95e8dae955c65ac8c1333fbdc152551507778d87 Mon Sep 17 00:00:00 2001 From: LauraUmana <11620537+LauraUmana@users.noreply.github.com> Date: Tue, 10 Sep 2024 20:50:50 -0400 Subject: [PATCH 25/26] updated Advisory Committee page --- components/OurTeam/AdvisoryBoard.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/OurTeam/AdvisoryBoard.tsx b/components/OurTeam/AdvisoryBoard.tsx index 76b0f7ac5..b7949abb2 100644 --- a/components/OurTeam/AdvisoryBoard.tsx +++ b/components/OurTeam/AdvisoryBoard.tsx @@ -27,8 +27,8 @@ export const AdvisoryBoard = () => { { /> Date: Tue, 10 Sep 2024 22:57:05 -0400 Subject: [PATCH 26/26] ran yarn fix --- .../GoalsAndMissionCardContent/GoalsAndMissionCardContent.tsx | 3 +-- components/OurTeam/SteeringCommittee.tsx | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/components/GoalsAndMissionCardContent/GoalsAndMissionCardContent.tsx b/components/GoalsAndMissionCardContent/GoalsAndMissionCardContent.tsx index 5be83185b..09e5459dd 100644 --- a/components/GoalsAndMissionCardContent/GoalsAndMissionCardContent.tsx +++ b/components/GoalsAndMissionCardContent/GoalsAndMissionCardContent.tsx @@ -137,8 +137,7 @@ const OurMissionCardContent = () => { - + > diff --git a/components/OurTeam/SteeringCommittee.tsx b/components/OurTeam/SteeringCommittee.tsx index 8d90578f5..8d0542de8 100644 --- a/components/OurTeam/SteeringCommittee.tsx +++ b/components/OurTeam/SteeringCommittee.tsx @@ -95,8 +95,7 @@ export const SteeringCommittee = () => { - + />