From d720fd64be6cae58460cb0c3bef73c3bb60812e9 Mon Sep 17 00:00:00 2001 From: jicruz96 Date: Wed, 6 Aug 2025 02:57:23 -0400 Subject: [PATCH 1/4] localize testimony counts titles and alt texts --- components/HotBillCard/Positions.tsx | 13 ++++++------- components/bill/TestimonyCounts.tsx | 12 ++++++------ public/locales/en/testimony.json | 19 ++++++++++++++----- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/components/HotBillCard/Positions.tsx b/components/HotBillCard/Positions.tsx index 1d9b293b0..7853376be 100644 --- a/components/HotBillCard/Positions.tsx +++ b/components/HotBillCard/Positions.tsx @@ -1,5 +1,4 @@ import React from "react" -import { Container, CardImg } from "react-bootstrap" import Image from "react-bootstrap/Image" import styled from "styled-components" import { useTranslation } from "next-i18next" @@ -14,29 +13,29 @@ export const Positions = (props: { return ( -

Endorse

+

{t("counts.endorsements.title")}

- {t("counts.endorsements")} + {t("counts.endorsements.alt")}

{props.endorseCount}

-

Neutral

+

{t("counts.neutral.title")}

{t("counts.neutral")}

{props.neutralCount}

-

Oppose

+

{t("counts.oppose.title")}

{t("counts.oppose")}

{props.opposeCount}

diff --git a/components/bill/TestimonyCounts.tsx b/components/bill/TestimonyCounts.tsx index 23ccee792..52632fc91 100644 --- a/components/bill/TestimonyCounts.tsx +++ b/components/bill/TestimonyCounts.tsx @@ -66,11 +66,11 @@ export const TestimonyCounts = ({ {total} Total Testimonies - Endorse + {t("counts.endorsements.title")} @@ -79,11 +79,11 @@ export const TestimonyCounts = ({ - Neutral + {t("counts.neutral.title")} @@ -92,11 +92,11 @@ export const TestimonyCounts = ({ - Oppose + {t("counts.oppose.title")} diff --git a/public/locales/en/testimony.json b/public/locales/en/testimony.json index b40290e83..3641724f6 100644 --- a/public/locales/en/testimony.json +++ b/public/locales/en/testimony.json @@ -1,9 +1,18 @@ { "counts": { - "endorsements": "The total number of testimonies that endorse the bill.", - "neutral":"The total number of testimonies that are neutral towards the bill.", - "oppose":"The total number of testimonies that oppose the bill." + "endorsements": { + "title": "Endorse", + "alt": "The total number of testimonies that endorse the bill." }, + "neutral": { + "title": "Neutral", + "alt": "The total number of testimonies that are neutral towards the bill." + }, + "oppose": { + "title": "Oppose", + "alt": "The total number of testimonies that oppose the bill." + } + }, "link": { "tweetContent": "I provided testimony on Bill {{billNumber}}. See {{link}} for details.", "twitter": "Tweet Your Published Testimony" @@ -61,7 +70,7 @@ "reporting": "Reporting", "report": "Report", "rescind": "You may request that your testimony be deleted by completing this form. Since MAPLE is an archive, deletion requests will only be granted if the testimony was submitted on the wrong bill, if it contained sensitive personal information, or if the user is below 18 years old.", - "personalInformation": "Personal Information", + "personalInformation": "Personal Information", "wrongBill": "Submitted to wrong bill", "offensive": "Offensive", "violent": "Violent", @@ -156,4 +165,4 @@ "draft": "Draft", "emailCta": "Email Your Published Testimony" } -} \ No newline at end of file +} From e3ee4401505f55e0c42163ed2462cf1d25f5d20f Mon Sep 17 00:00:00 2001 From: Mephistic Date: Sun, 10 Aug 2025 14:17:06 -0400 Subject: [PATCH 2/4] Revert "[1753] Replace custom routing with react-instantsearch-router-nextjs" --- components/search/bills/BillSearch.tsx | 18 ++---- components/search/routingHelpers.ts | 36 ------------ .../search/testimony/TestimonySearch.tsx | 16 +----- components/search/useRouting.tsx | 55 +++++++++++++++++++ package.json | 1 - yarn.lock | 55 ------------------- 6 files changed, 62 insertions(+), 119 deletions(-) delete mode 100644 components/search/routingHelpers.ts create mode 100644 components/search/useRouting.tsx diff --git a/components/search/bills/BillSearch.tsx b/components/search/bills/BillSearch.tsx index 80cefa3ec..faadd018e 100644 --- a/components/search/bills/BillSearch.tsx +++ b/components/search/bills/BillSearch.tsx @@ -7,23 +7,21 @@ import { SearchBox, useInstantSearch } from "react-instantsearch" -import { createInstantSearchRouterNext } from "react-instantsearch-router-nextjs" -import singletonRouter from "next/router" +import { currentGeneralCourt } from "functions/src/shared" import styled from "styled-components" import TypesenseInstantSearchAdapter from "typesense-instantsearch-adapter" -import { currentGeneralCourt } from "functions/src/shared" import { Col, Container, Row, Spinner } from "../../bootstrap" import { NoResults } from "../NoResults" import { ResultCount } from "../ResultCount" import { SearchContainer } from "../SearchContainer" import { SearchErrorBoundary } from "../SearchErrorBoundary" +import { useRouting } from "../useRouting" import { BillHit } from "./BillHit" import { useBillRefinements } from "./useBillRefinements" import { SortBy, SortByWithConfigurationItem } from "../SortBy" import { getServerConfig, VirtualFilters } from "../common" import { useBillSort } from "./useBillSort" import { FC, useState } from "react" -import { pathToSearchState, searchStateToUrl } from "../routingHelpers" const searchClient = new TypesenseInstantSearchAdapter({ server: getServerConfig(), @@ -72,16 +70,8 @@ export const BillSearch = () => { } }} searchClient={searchClient} - routing={{ - router: createInstantSearchRouterNext({ - singletonRouter, - routerOptions: { - cleanUrlOnDispose: false, - createURL: args => searchStateToUrl(args), - parseURL: args => pathToSearchState(args) - } - }) - }} + routing={useRouting()} + future={{ preserveSharedStateOnUnmount: true }} > diff --git a/components/search/routingHelpers.ts b/components/search/routingHelpers.ts deleted file mode 100644 index 42e139b30..000000000 --- a/components/search/routingHelpers.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { UiState } from "instantsearch.js" -import QueryString from "qs" - -export const searchStateToUrl = (createUrlArgs: { - location: Location - qsModule: typeof QueryString - routeState: UiState -}) => { - const { location, qsModule: qs, routeState: searchState } = createUrlArgs - const base = location.origin + location.pathname - - const flagQueries = Object.fromEntries( - Object.entries(qs.parse(window.location.search.slice(1))).filter( - ([key]) => !Object.keys(searchState).includes(key) - ) - ) - - const query = qs.stringify({ - ...searchState, - ...flagQueries - }) - - return query ? `${base}?${query}` : base -} - -export const pathToSearchState = (parseUrlArgs: { - location: Location - qsModule: typeof QueryString -}) => { - const { location, qsModule: qs } = parseUrlArgs - const path = location.href - - return ( - path.includes("?") ? qs.parse(path.substring(path.indexOf("?") + 1)) : {} - ) as UiState -} diff --git a/components/search/testimony/TestimonySearch.tsx b/components/search/testimony/TestimonySearch.tsx index f9fe19271..e77b42645 100644 --- a/components/search/testimony/TestimonySearch.tsx +++ b/components/search/testimony/TestimonySearch.tsx @@ -6,8 +6,6 @@ import { SearchBox, useInstantSearch } from "react-instantsearch" -import { createInstantSearchRouterNext } from "react-instantsearch-router-nextjs" -import singletonRouter from "next/router" import { StyledTabContent, StyledTabNav @@ -25,10 +23,10 @@ import { SearchContainer } from "../SearchContainer" import { SearchErrorBoundary } from "../SearchErrorBoundary" import { SortBy } from "../SortBy" import { getServerConfig, VirtualFilters } from "../common" +import { useRouting } from "../useRouting" import { TestimonyHit } from "./TestimonyHit" import { useTestimonyRefinements } from "./useTestimonyRefinements" import { FollowContext, OrgFollowStatus } from "components/shared/FollowContext" -import { pathToSearchState, searchStateToUrl } from "../routingHelpers" const searchClient = new TypesenseInstantSearchAdapter({ server: getServerConfig(), @@ -65,16 +63,8 @@ export const TestimonySearch = () => ( } }} searchClient={searchClient} - routing={{ - router: createInstantSearchRouterNext({ - singletonRouter, - routerOptions: { - cleanUrlOnDispose: false, - createURL: args => searchStateToUrl(args), - parseURL: args => pathToSearchState(args) - } - }) - }} + routing={useRouting()} + future={{ preserveSharedStateOnUnmount: true }} > diff --git a/components/search/useRouting.tsx b/components/search/useRouting.tsx new file mode 100644 index 000000000..e4ef3b9fc --- /dev/null +++ b/components/search/useRouting.tsx @@ -0,0 +1,55 @@ +import { UiState } from "instantsearch.js" +import { RouterProps } from "instantsearch.js/es/middlewares" +import Router from "next/router" +import qs from "qs" +import { useMemo } from "react" + +const pathToSearchState = (path: string) => + (path.includes("?") + ? qs.parse(path.substring(path.indexOf("?") + 1)) + : {}) as UiState + +const searchStateToUrl = (searchState: UiState) => { + const base = window.location.pathname + + const flagQueries = Object.fromEntries( + Object.entries(qs.parse(window.location.search.slice(1))).filter( + ([key]) => !Object.keys(searchState).includes(key) + ) + ) + + const query = qs.stringify({ + ...searchState, + ...flagQueries + }) + + return query ? `${base}?${query}` : base +} + +export function useRouting(): RouterProps { + return useMemo(() => { + let disposed = false + return { + router: { + createURL: searchStateToUrl, + dispose() { + disposed = true + // Clear back listener + Router.beforePopState(() => true) + }, + onUpdate(callback) { + Router.beforePopState(({ url }) => { + callback(pathToSearchState(url)) + return true + }) + }, + read: () => pathToSearchState(window.location.href), + write(route) { + if (disposed) return + const url = searchStateToUrl(route) + Router.push(url, url, { shallow: true }) + } + } + } + }, []) +} diff --git a/package.json b/package.json index 69d09debe..1d006efd6 100644 --- a/package.json +++ b/package.json @@ -118,7 +118,6 @@ "react-i18next": "^13.2.2", "react-inlinesvg": "^3.0.1", "react-instantsearch": "^7.12.4", - "react-instantsearch-router-nextjs": "^7.15.5", "react-is": "^18.2.0", "react-markdown": "^8.0.4", "react-overlays": "^5.1.1", diff --git a/yarn.lock b/yarn.lock index c3169cf13..ceef2062b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5291,13 +5291,6 @@ algoliasearch-helper@3.22.5: dependencies: "@algolia/events" "^4.0.1" -algoliasearch-helper@3.24.3: - version "3.24.3" - resolved "https://registry.yarnpkg.com/algoliasearch-helper/-/algoliasearch-helper-3.24.3.tgz#9a358c3110bcd912e79ef606a6e7bdd7725d22ee" - integrity sha512-3QKg5lzSfUiPN8Hn1ViHEGv6PjK7i4SFEDLzwlSzPO/4mVOsyos7B7/AsEtFQW5KHHPiCq6DyJl+mzg7CYlEgw== - dependencies: - "@algolia/events" "^4.0.1" - all-contributors-cli@^6.20.5: version "6.26.1" resolved "https://registry.yarnpkg.com/all-contributors-cli/-/all-contributors-cli-6.26.1.tgz#9f3358c9b9d0a7e66c8f84ffebf5a6432a859cae" @@ -10408,13 +10401,6 @@ install-artifact-from-github@^1.3.5: resolved "https://registry.yarnpkg.com/install-artifact-from-github/-/install-artifact-from-github-1.3.5.tgz#88c96fe40e5eb21d45586d564208c648a1dbf38d" integrity sha512-gZHC7f/cJgXz7MXlHFBxPVMsvIbev1OQN1uKQYKVJDydGNm9oYf9JstbU4Atnh/eSvk41WtEovoRm+8IF686xg== -instantsearch-ui-components@0.11.1: - version "0.11.1" - resolved "https://registry.yarnpkg.com/instantsearch-ui-components/-/instantsearch-ui-components-0.11.1.tgz#664ca03f657079946e459af72fa8d2674799c466" - integrity sha512-ZqUbJYYgObQ47J08ftXV1KNC1vdEoiD4/49qrkCdW46kRzLxLgYXJGuEuk48DQwK4aBtIoccgTyfbMGfcqNjxg== - dependencies: - "@babel/runtime" "^7.1.2" - instantsearch-ui-components@0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/instantsearch-ui-components/-/instantsearch-ui-components-0.9.0.tgz#f7ae71fe623d18eff32b73071749f31826cb7b89" @@ -10445,24 +10431,6 @@ instantsearch.js@4.74.2: qs "^6.5.1 < 6.10" search-insights "^2.15.0" -instantsearch.js@4.78.1: - version "4.78.1" - resolved "https://registry.yarnpkg.com/instantsearch.js/-/instantsearch.js-4.78.1.tgz#cee799b920ba08c7c4e5af5ba591b86a1d80af1d" - integrity sha512-nDTWQ6DUxYzBZfkSxb/QJsYMZPPU8SGlGurn9147ABvA5Eumtxmk3Qy55EBMl0VxKVltGy3axAYMRB/gKIIHkg== - dependencies: - "@algolia/events" "^4.0.1" - "@types/dom-speech-recognition" "^0.0.1" - "@types/google.maps" "^3.55.12" - "@types/hogan.js" "^3.0.0" - "@types/qs" "^6.5.3" - algoliasearch-helper "3.24.3" - hogan.js "^3.0.2" - htm "^3.0.0" - instantsearch-ui-components "0.11.1" - preact "^10.10.0" - qs "^6.5.1 < 6.10" - search-insights "^2.17.2" - instantsearch.js@^4.43.0: version "4.62.0" resolved "https://registry.yarnpkg.com/instantsearch.js/-/instantsearch.js-4.62.0.tgz#68577f4f04866728f22441cbc7464c544678d342" @@ -14837,24 +14805,6 @@ react-instantsearch-core@7.13.2: instantsearch.js "4.74.2" use-sync-external-store "^1.0.0" -react-instantsearch-core@7.15.5: - version "7.15.5" - resolved "https://registry.yarnpkg.com/react-instantsearch-core/-/react-instantsearch-core-7.15.5.tgz#65d1edc440de8dc73d55230d13af8cbcf1724221" - integrity sha512-SFxiwwMf0f5F/8U0Y4ullvQ7bZtbYE516UOJbxaHhjV8yY0i8c22K4lrBFrYbxVRT7QAcp2wLGHiB7r/lD7eRA== - dependencies: - "@babel/runtime" "^7.1.2" - algoliasearch-helper "3.24.3" - instantsearch.js "4.78.1" - use-sync-external-store "^1.0.0" - -react-instantsearch-router-nextjs@^7.15.5: - version "7.15.5" - resolved "https://registry.yarnpkg.com/react-instantsearch-router-nextjs/-/react-instantsearch-router-nextjs-7.15.5.tgz#a8b13bc5ad9bd8c5a689d48f2714eab6bed2514f" - integrity sha512-kn325Nl6QkZlkSuOXwKUOb56QkSsKes9XQdBLythKt2oZzzAfcaXSYzYsFEyj96cMYDLkRHhHvLhdyq4C8Xezg== - dependencies: - instantsearch.js "4.78.1" - react-instantsearch-core "7.15.5" - react-instantsearch@^7.12.4: version "7.13.2" resolved "https://registry.yarnpkg.com/react-instantsearch/-/react-instantsearch-7.13.2.tgz#db84d04bd399596fb0078625bc75a6abc65e4bc6" @@ -15657,11 +15607,6 @@ search-insights@^2.15.0: resolved "https://registry.yarnpkg.com/search-insights/-/search-insights-2.17.2.tgz#d13b2cabd44e15ade8f85f1c3b65c8c02138629a" integrity sha512-zFNpOpUO+tY2D85KrxJ+aqwnIfdEGi06UH2+xEb+Bp9Mwznmauqc9djbnBibJO5mpfUPPa8st6Sx65+vbeO45g== -search-insights@^2.17.2: - version "2.17.3" - resolved "https://registry.yarnpkg.com/search-insights/-/search-insights-2.17.3.tgz#8faea5d20507bf348caba0724e5386862847b661" - integrity sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ== - search-insights@^2.6.0: version "2.11.0" resolved "https://registry.yarnpkg.com/search-insights/-/search-insights-2.11.0.tgz#0512ae3b801fed5ff3a2ae82840bf20ba29d82e5" From 0d26f0fc8e150d88c986518a940c0fdf92356d39 Mon Sep 17 00:00:00 2001 From: Mephistic Date: Sun, 10 Aug 2025 16:10:07 -0400 Subject: [PATCH 3/4] chore(transcriptions): Update firestore rules to allow read-only access to transcription paragraphs --- firestore.rules | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/firestore.rules b/firestore.rules index 9ce36c3d7..e33d279e2 100644 --- a/firestore.rules +++ b/firestore.rules @@ -99,6 +99,12 @@ service cloud.firestore { allow read: if true allow write: if false } + + // public, read-only + match /paragraphs/{pid} { + allow read: if true + allow write: if false + } } } } \ No newline at end of file From afbc40d0932ee220beb1f39d1abeb3b737eb1a25 Mon Sep 17 00:00:00 2001 From: jicruz96 Date: Mon, 11 Aug 2025 15:18:11 -0400 Subject: [PATCH 4/4] remove stale HotBillCard --- components/HotBillCard/HotBillCard.tsx | 39 --------- components/HotBillCard/Positions.tsx | 80 ------------------- scripts/stories.yml | 5 -- .../newsfeed/HotBillCard.stories.tsx | 68 ---------------- 4 files changed, 192 deletions(-) delete mode 100644 components/HotBillCard/HotBillCard.tsx delete mode 100644 components/HotBillCard/Positions.tsx delete mode 100644 stories_hold/organisms/newsfeed/HotBillCard.stories.tsx diff --git a/components/HotBillCard/HotBillCard.tsx b/components/HotBillCard/HotBillCard.tsx deleted file mode 100644 index 5816543fc..000000000 --- a/components/HotBillCard/HotBillCard.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { CardTitle, ListItem } from "components/Card" -import { Card as MapleCard } from "../Card/Card" -import { Positions } from "./Positions" - -type bill = { - id: string - billNumber: string - title: string - endorseCount: number - opposeCount: number - neutralCount: number -} - -export const HotBillCard = (props: { - bills: bill[] - selectedBillId: string - session: string -}) => { - const items = props.bills.map((bill, index) => { - return ( - - } - /> - ) - }) - - const header = - - return -} diff --git a/components/HotBillCard/Positions.tsx b/components/HotBillCard/Positions.tsx deleted file mode 100644 index 7853376be..000000000 --- a/components/HotBillCard/Positions.tsx +++ /dev/null @@ -1,80 +0,0 @@ -import React from "react" -import Image from "react-bootstrap/Image" -import styled from "styled-components" -import { useTranslation } from "next-i18next" - -export const Positions = (props: { - endorseCount: number - opposeCount: number - neutralCount: number -}) => { - const { t } = useTranslation("testimony") - - return ( - - -

{t("counts.endorsements.title")}

-
- {t("counts.endorsements.alt")} -

{props.endorseCount}

-
-
- -

{t("counts.neutral.title")}

-
- {t("counts.neutral.alt")} -

{props.neutralCount}

-
-
- -

{t("counts.oppose.title")}

-
- {t("counts.oppose.alt")} -

{props.opposeCount}

-
-
-
- ) -} - -const PositionsStyle = styled.div` - display: flex; - margin-right: 5%; - - font-family: "Nunito"; - font-style: normal; - - @media (max-width: 1250px) { - margin-right: 10%; - } -` -const PositionStyle = styled.div` - display: flex; - flex-direction: column; - align-items: center; - margin-left: 10%; - margin-bottom: 0; - .stanceTitle { - color: #8999d6; - } - p { - margin: 0; - } - div { - margin: 5%; - display: flex; - align-items: center; - text-align: center; - .svg { - margin-right: 5%; - } - } -` diff --git a/scripts/stories.yml b/scripts/stories.yml index 3db5579a0..b3efee5d4 100644 --- a/scripts/stories.yml +++ b/scripts/stories.yml @@ -134,11 +134,6 @@ figmaUrl: https://www.figma.com/file/3ifz37EOwDfmnEG8320KlD/CS1---MAPLE?node-id= # Dashboard Newsfeed --- -name: HotBillCard -folder: dashboard/newsfeed -grouping: Dashboard/Newsfeed -figmaUrl: https://www.figma.com/file/3ifz37EOwDfmnEG8320KlD/CS1---MAPLE?node-id=158%3A3865 ---- name: NewsfeedCard folder: dashboard/newsfeed grouping: Dashboard/Newsfeed diff --git a/stories_hold/organisms/newsfeed/HotBillCard.stories.tsx b/stories_hold/organisms/newsfeed/HotBillCard.stories.tsx deleted file mode 100644 index 818384bc5..000000000 --- a/stories_hold/organisms/newsfeed/HotBillCard.stories.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import { ComponentStory } from "@storybook/react" -import React, { useState } from "react" -import { createMeta } from "stories/utils" -import { HotBillCard } from "components/HotBillCard/HotBillCard" - -// TODO: move into components directory -//const HotBillCard = () =>
TODO
- -export default createMeta({ - title: "Dashboard/Newsfeed/HotBillCard", - component: HotBillCard -}) - -const Template: ComponentStory = props => { - return -} - -export const Primary = Template.bind({}) -Primary.args = { - bills: [ - { - id: "123", - billNumber: "hc.508", - title: - "An Act that goes by no other name but... I forget. But it was good", - endorseCount: 41, - opposeCount: 182, - neutralCount: 98 - }, - { - id: "456", - billNumber: "hc.411", - title: - "An Act that goes by no other name but... I forget. But it was good", - endorseCount: 41, - opposeCount: 182, - neutralCount: 98 - }, - { - id: "789", - billNumber: "hc.999", - title: - "An Act that goes by no other name but... I forget. But it was good", - endorseCount: 41, - opposeCount: 182, - neutralCount: 98 - }, - { - id: "012", - billNumber: "hc.911", - title: - "An Act that goes by no other name but... I forget. But it was good", - endorseCount: 41, - opposeCount: 182, - neutralCount: 98 - }, - { - id: "345", - billNumber: "hc.888", - title: - "An Act that goes by no other name but... I forget. But it was good", - endorseCount: 41, - opposeCount: 182, - neutralCount: 98 - } - ], - session: "123" -}