Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions components/search/NoResults.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ const Container = styled.div`
export const NoResults: React.FC<React.PropsWithChildren<unknown>> = ({
children
}) => {
const { t } = useTranslation("common")
const { t } = useTranslation("search")
return (
<Container>
<Image src="/no-results.svg" alt={t("noResults")} />
<div className="fs-3">Looks Pretty Empty Here</div>
<Image src="/no-results.svg" alt={t("no_results")} />
<div className="fs-3">{t("looks_pretty_empty_here")}</div>
<div className="text-center">{children}</div>
</Container>
)
Expand Down
7 changes: 6 additions & 1 deletion components/search/ResultCount.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useTranslation } from "next-i18next"
import { useStats } from "react-instantsearch"
import styled from "styled-components"

Expand All @@ -13,7 +14,11 @@ export function ResultCount(props: any) {

return (
<ResultContainer {...props}>
Showing {pageStart}-{pageEnd} of {nbHits} Results
{useTranslation("search").t("result_count", {
pageStart,
pageEnd,
nbHits
})}
</ResultContainer>
)
}
14 changes: 9 additions & 5 deletions components/search/SearchErrorBoundary.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import React, { ReactNode } from "react"
import { Alert } from "react-bootstrap"
import { withTranslation, WithTranslation } from "next-i18next"

export class SearchErrorBoundary extends React.Component<{
children?: ReactNode
}> {
class SearchErrorBoundaryBase extends React.Component<
{ children?: ReactNode } & WithTranslation
> {
state: { error: string | null } = { error: null }

promiseRejectionHandler = (event: PromiseRejectionEvent) => {
Expand All @@ -16,8 +17,7 @@ export class SearchErrorBoundary extends React.Component<{
if (this.state.error) {
return (
<Alert variant="danger">
Something went wrong. Please try again. Original message:{" "}
{this.state.error}
{this.props.t("search_error", { error: this.state.error })}
</Alert>
)
}
Expand All @@ -44,3 +44,7 @@ export class SearchErrorBoundary extends React.Component<{
)
}
}

export const SearchErrorBoundary = withTranslation("search")(
SearchErrorBoundaryBase
)
2 changes: 1 addition & 1 deletion components/search/bills/BillSearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ const Layout: FC<
const refinements = useBillRefinements()
const status = useSearchStatus()

const { t } = useTranslation("billSearch")
const { t } = useTranslation("search")

return (
<SearchContainer>
Expand Down
17 changes: 0 additions & 17 deletions components/search/bills/useBillHierarchicalMenu.tsx

This file was deleted.

82 changes: 30 additions & 52 deletions components/search/bills/useBillRefinements.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { generalCourts } from "functions/src/shared"
import { RefinementListItem } from "instantsearch.js/es/connectors/refinement-list/connectRefinementList"
import { useCallback } from "react"
import { useMemo } from "react"
import { useRefinements } from "../useRefinements"
import { useTranslation } from "next-i18next"

// for legacy code purposes, things like:
//
Expand All @@ -17,58 +18,35 @@ import { useRefinements } from "../useRefinements"
// searchablePlaceholder: "Legislative Session",

export const useBillRefinements = () => {
const baseProps = { limit: 500, searchable: true }
const propsList = [
{
transformItems: useCallback(
(i: RefinementListItem[]) =>
i
.map(i => ({
...i,
label: generalCourts[i.value as any]?.Name ?? i.label
}))
.sort((a, b) => Number(b.value) - Number(a.value)),
[]
),
attribute: "court",
searchablePlaceholder: "Legislative Session",
...baseProps
},
{
attribute: "currentCommittee",
...baseProps,
searchablePlaceholder: "Current Committee"
},
{
attribute: "city",
searchablePlaceholder: "City",
...baseProps
},
{
attribute: "primarySponsor",
...baseProps,
searchablePlaceholder: "Primary Sponsor"
},
{
attribute: "cosponsors",
...baseProps,
searchablePlaceholder: "Cosponsor"
}
]

const hierarchicalPropsList = [
{
attribute: "topics.lvl0",
...baseProps
},
{
attribute: "topics.lvl1",
...baseProps
}
]
const { t } = useTranslation("search")

return useRefinements({
hierarchicalMenuProps: hierarchicalPropsList,
refinementProps: propsList
hierarchicalMenuProps: { attributes: ["topics.lvl0", "topics.lvl1"] },
refinementProps: useMemo(
() =>
[
{
transformItems: (items: RefinementListItem[]) =>
items
.map(i => ({
...i,
label: generalCourts[parseInt(i.value, 10)]?.Name ?? i.label
}))
.sort((a, b) => Number(b.value) - Number(a.value)),

attribute: "court"
},
{ attribute: "currentCommittee" },
{ attribute: "city" },
{ attribute: "primarySponsor" },
{ attribute: "cosponsors" }
].map(props => ({
limit: 500,
searchable: true,
searchablePlaceholder: t(`refinements.bill.${props.attribute}`),
...props
})),
[t]
)
})
}
14 changes: 8 additions & 6 deletions components/search/bills/useBillSort.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,33 @@
import { useMemo, useRef } from "react"
import { SortByWithConfigurationItem } from "../SortBy"
import { useTranslation } from "next-i18next"

export const useBillSort = () => {
const now = useRef(new Date().getTime())
const { t } = useTranslation("search")

// refer to
// https://github.com/typesense/typesense-instantsearch-adapter#with-react-instantsearch
const items: SortByWithConfigurationItem[] = useMemo(
() => [
{
label: "Sort by Most Recent Testimony",
label: t("sort_by.most_recent_testimony"),
value: "bills/sort/latestTestimonyAt:desc"
},
{
label: "Sort by Relevance",
label: t("sort_by.relevance"),
value: "bills/sort/_text_match:desc,testimonyCount:desc"
},
{
label: "Sort by Testimony Count",
label: t("sort_by.testimony_count"),
value: "bills/sort/testimonyCount:desc"
},
{
label: "Sort by Cosponsor Count",
label: t("sort_by.cosponsor_count"),
value: "bills/sort/cosponsorCount:desc"
},
{
label: "Sort by Next Hearing Date",
label: t("sort_by.next_hearing_date"),
value: "bills/sort/nextHearingAt:asc",
configure: {
numericRefinements: {
Expand All @@ -36,7 +38,7 @@ export const useBillSort = () => {
}
}
],
[]
[t]
)
return items
}
33 changes: 21 additions & 12 deletions components/search/testimony/TestimonyHit.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Hit } from "instantsearch.js"
import Link from "next/link"
import { useTranslation } from "next-i18next"
import { Trans, useTranslation } from "next-i18next"
import { Image } from "react-bootstrap"
import { useMediaQuery } from "usehooks-ts"

Expand All @@ -25,8 +25,6 @@ export const TestimonyHit = ({ hit }: { hit: Hit<Testimony> }) => {
}

const TestimonyResult = ({ hit }: { hit: Hit<Testimony> }) => {
const { t } = useTranslation(["auth"])

const date = new Date(
parseInt(hit.publishedAt.toString())
).toLocaleDateString("en-US", {
Expand All @@ -37,12 +35,6 @@ const TestimonyResult = ({ hit }: { hit: Hit<Testimony> }) => {
const { loading, error, result: bill } = useBill(hit.court, hit.billId)
const committee = bill?.currentCommittee
const isOrg = hit.authorRole === "organization"
const writtenBy =
isOrg || hit.public ? (
<Link href={`/profile?id=${hit.authorUid}`}>{hit.fullName}</Link>
) : (
hit.fullName
)
const { user } = useAuth()
const { followOrg } = useFlags()
const isCurrentUser = user?.uid === hit.authorUid
Expand All @@ -67,12 +59,25 @@ const TestimonyResult = ({ hit }: { hit: Hit<Testimony> }) => {
>
<Image
src={isOrg ? "/profile-org-icon.svg" : "/profile-individual-icon.svg"}
alt={t("profileIcon")}
alt={useTranslation("auth").t("profileIcon")}
height="30px"
width="30px"
/>
<span style={{ flexGrow: 1 }}>
<b>Written by {writtenBy}</b>
<b>
<Trans
ns="testimony"
i18nKey="testimonyHit.writtenBy"
values={{ author: hit.fullName }}
components={[
isOrg || hit.public ? (
<Link href={`/profile?id=${hit.authorUid}`} />
) : (
<></>
)
]}
/>
</b>
</span>
{hit.public && !isCurrentUser && followOrg && user && (
<FollowUserButton profileId={hit.authorUid} />
Expand All @@ -95,7 +100,11 @@ const TestimonyResult = ({ hit }: { hit: Hit<Testimony> }) => {
<div style={{ display: "flex", alignItems: "center", gap: "15px" }}>
{/* <Link href={maple.bill({ court: hit.court, id: hit.billId })}> */}
{/* <a> */}
<h2>Bill #{formatBillId(hit.billId)}</h2>
<h2>
{useTranslation("testimony").t("testimonyHit.bill", {
billId: formatBillId(hit.billId)
})}
</h2>
{/* </a> */}
{/* </Link> */}
{committee && (
Expand Down
Loading