Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: bill follow and unfollow functionality to testimony page #1661

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
131 changes: 64 additions & 67 deletions components/bill/BillDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,86 +37,83 @@ export const BillDetails = ({ bill }: BillProps) => {
const isPendingUpgrade = useAuth().claims?.role === "pendingUpgrade"
const flags = useFlags()

const [followStatus, setFollowStatus] = useState<OrgFollowStatus>({})
const { user } = useAuth()

return (
<>
<FollowContext.Provider value={{ followStatus, setFollowStatus }}>
{isPendingUpgrade && <PendingUpgradeBanner />}
{!isCurrentCourt(bill.court) && (
<Banner>{t("bill.old_session", { billCourt: bill.court })}</Banner>
)}
{isPendingUpgrade && <PendingUpgradeBanner />}
{!isCurrentCourt(bill.court) && (
<Banner>{t("bill.old_session", { billCourt: bill.court })}</Banner>
)}

<StyledContainer className="mt-3 mb-3">
<Row>
<Col>
<Back href="/bills">{t("back_to_bills")}</Back>
</Col>
</Row>
{bill.history.length > 0 ? (
<>
<Row className="align-items-end justify-content-start">
<Col md={2}>
<BillNumber bill={bill} />
</Col>
<Col
xs={10}
md={6}
className="mb-3 ms-auto d-flex justify-content-end"
>
<Status bill={bill} />
</Col>
</Row>
<Row className="mb-4">
<Col xs={12} className="d-flex justify-content-end">
{flags.notifications && user && (
<FollowBillButton bill={bill} />
)}
</Col>
</Row>
</>
) : (
<Row>
<Col>
<StyledContainer className="mt-3 mb-3">
<Row>
<Col>
<Back href="/bills">{t("back_to_bills")}</Back>
</Col>
</Row>
{bill.history.length > 0 ? (
<>
<Row className="align-items-end justify-content-start">
<Col md={2}>
<BillNumber bill={bill} />
</Col>
<Col xs={6} className="d-flex justify-content-end">
<Styled>
{flags.notifications && user && (
<FollowBillButton bill={bill} />
)}
</Styled>
<Col
xs={10}
md={6}
className="mb-3 ms-auto d-flex justify-content-end"
>
<Status bill={bill} />
</Col>
</Row>
)}
<Row className="mt-2">
<Col>
<Summary bill={bill} />
</Col>
</Row>
<Row className="mb-4">
<Col xs={12} className="d-flex justify-content-end">
{flags.notifications && user && (
<FollowBillButton bill={bill} />
)}
</Col>
</Row>
</>
) : (
<Row>
<Col md={8}>
<Sponsors bill={bill} className="mt-4 pb-1" />
<BillTestimonies bill={bill} className="mt-4" />
{flags.lobbyingTable && (
<LobbyingTable bill={bill} className="mt-4 pb-1" />
)}
<Col>
<BillNumber bill={bill} />
</Col>
<Col md={4}>
<Committees bill={bill} className="mt-4 pb-1" />
<Hearing
bill={bill}
className="bg-secondary d-flex justify-content-center mt-4 pb-1 text-light"
/>
<TestimonyFormPanel bill={bill} />
{flags.billTracker && (
<BillTrackerConnectedView bill={bill} className="mt-4" />
)}
<Col xs={6} className="d-flex justify-content-end">
<Styled>
{flags.notifications && user && (
<FollowBillButton bill={bill} />
)}
</Styled>
</Col>
</Row>
</StyledContainer>
</FollowContext.Provider>
)}
<Row className="mt-2">
<Col>
<Summary bill={bill} />
</Col>
</Row>
<Row>
<Col md={8}>
<Sponsors bill={bill} className="mt-4 pb-1" />
<BillTestimonies bill={bill} className="mt-4" />
{flags.lobbyingTable && (
<LobbyingTable bill={bill} className="mt-4 pb-1" />
)}
</Col>
<Col md={4}>
<Committees bill={bill} className="mt-4 pb-1" />
<Hearing
bill={bill}
className="bg-secondary d-flex justify-content-center mt-4 pb-1 text-light"
/>
<TestimonyFormPanel bill={bill} />
{flags.billTracker && (
<BillTrackerConnectedView bill={bill} className="mt-4" />
)}
</Col>
</Row>
</StyledContainer>
</>
)
}
25 changes: 15 additions & 10 deletions components/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import AuthModal from "./auth/AuthModal"
import PageFooter from "./Footer/Footer"
import { MainNavbar } from "./Navbar"
import { TabContext, TabStatus } from "./shared/ProfileTabsContext"
import { FollowContext, OrgFollowStatus } from "./shared/FollowContext"

export const PageContainer: FC<React.PropsWithChildren<unknown>> = ({
children
Expand Down Expand Up @@ -36,6 +37,8 @@ export const Layout: React.FC<React.PropsWithChildren<LayoutProps>> = ({
setIsClient(true)
}, [])

const [followStatus, setFollowStatus] = useState<OrgFollowStatus>({})

return (
<>
{isClient ? (
Expand All @@ -45,16 +48,18 @@ export const Layout: React.FC<React.PropsWithChildren<LayoutProps>> = ({
<link rel="icon" href="/favicon.ico" />
</Head>
<TabContext.Provider value={{ tabStatus, setTabStatus }}>
<PageContainer>
<MainNavbar />
<AuthModal />
<div className={`col`}>{children}</div>
<PageFooter
authenticated={authenticated}
user={user as any}
signOut={signOutAndRedirectToHome}
/>
</PageContainer>
<FollowContext.Provider value={{ followStatus, setFollowStatus }}>
<PageContainer>
<MainNavbar />
<AuthModal />
<div className={`col`}>{children}</div>
<PageFooter
authenticated={authenticated}
user={user as any}
signOut={signOutAndRedirectToHome}
/>
</PageContainer>
</FollowContext.Provider>
</TabContext.Provider>
</>
) : (
Expand Down
54 changes: 49 additions & 5 deletions components/testimony/TestimonyDetailPage/PolicyActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,22 @@ import { Card, ListItem, ListItemProps } from "components/Card"
import { useFlags } from "components/featureFlags"
import { formatBillId } from "components/formatting"
import { formUrl } from "components/publish"
import { isNotNull } from "components/utils"
import { FC, ReactElement } from "react"
import { FC, ReactElement, useContext, useEffect } from "react"
import { useCurrentTestimonyDetails } from "./testimonyDetailSlice"
import { useTranslation } from "next-i18next"
import { useAuth } from "components/auth"
import { TopicQuery } from "components/shared/FollowingQueries"
import { StyledImage } from "components/ProfilePage/StyledProfileComponents"
import { FollowContext } from "components/shared/FollowContext"

interface PolicyActionsProps {
className?: string
isUser?: boolean
isReporting: boolean
setReporting: (boolean: boolean) => void
topicName: string
followAction: () => Promise<void>
unfollowAction: () => Promise<void>
}

const PolicyActionItem: FC<React.PropsWithChildren<ListItemProps>> = props => (
Expand All @@ -22,19 +28,57 @@ export const PolicyActions: FC<React.PropsWithChildren<PolicyActionsProps>> = ({
className,
isUser,
isReporting,
setReporting
setReporting,
topicName,
followAction,
unfollowAction
}) => {
const { bill } = useCurrentTestimonyDetails(),
billLabel = formatBillId(bill.id)
const { notifications } = useFlags()

const { user } = useAuth()
const uid = user?.uid

const { followStatus, setFollowStatus } = useContext(FollowContext)

useEffect(() => {
uid
? TopicQuery(uid, topicName).then(result => {
setFollowStatus(prevOrgFollowGroup => {
return { ...prevOrgFollowGroup, [topicName]: Boolean(result) }
})
})
: null
}, [uid, topicName, setFollowStatus])

const FollowClick = async () => {
await followAction()
setFollowStatus({ ...followStatus, [topicName]: true })
}

const UnfollowClick = async () => {
await unfollowAction()
setFollowStatus({ ...followStatus, [topicName]: false })
}

const isFollowing = followStatus[topicName]
const text = isFollowing ? "Unfollow" : "Follow"
aaerhart marked this conversation as resolved.
Show resolved Hide resolved
const checkmark = isFollowing ? (
aaerhart marked this conversation as resolved.
Show resolved Hide resolved
<StyledImage src="/check-white.svg" alt="" />
) : null
const handleClick = (event: React.MouseEvent<Element, MouseEvent>) => {
event.preventDefault()
isFollowing ? UnfollowClick() : FollowClick()
}

const items: ReactElement[] = []
if (notifications)
items.push(
<PolicyActionItem
onClick={() => window.alert("TODO")} // TODO: add follow action here
onClick={e => handleClick(e)}
key="follow"
billName={`Follow ${billLabel}`}
billName={`${text} ${billLabel}`}
/>
)
items.push(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,27 @@ import { TestimonyDetail } from "./TestimonyDetail"
import { VersionBanner } from "./TestimonyVersionBanner"
import { useAuth } from "components/auth"
import { useMediaQuery } from "usehooks-ts"
import { setFollow, setUnfollow } from "components/shared/FollowingQueries"

export const TestimonyDetailPage: FC<React.PropsWithChildren<unknown>> = () => {
const [isReporting, setIsReporting] = useState(false)
const reportMutation = useReportTestimony()
const didReport = reportMutation.isError || reportMutation.isSuccess
const isMobile = useMediaQuery("(max-width: 768px)")
const { authorUid, revision } = useCurrentTestimonyDetails()
const { bill } = useCurrentTestimonyDetails()
const { user } = useAuth()
const isUser = user?.uid === authorUid
const handleReporting = (boolean: boolean) => {
setIsReporting(boolean)
}
const { t } = useTranslation("testimony", { keyPrefix: "reportModal" })
const uid = user?.uid
const { id: billId, court: courtId } = bill
const topicName = `bill-${courtId}-${billId}`
const followAction = () =>
setFollow(uid, topicName, bill, billId, courtId, undefined)
const unfollowAction = () => setUnfollow(uid, topicName)

return (
<>
Expand All @@ -49,6 +57,9 @@ export const TestimonyDetailPage: FC<React.PropsWithChildren<unknown>> = () => {
isUser={isUser}
isReporting={isReporting}
setReporting={handleReporting}
topicName={topicName}
followAction={followAction}
unfollowAction={unfollowAction}
/>
)}
<RevisionHistory />
Expand Down
Loading