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
108 changes: 76 additions & 32 deletions hillstack/src/app/_home/widgets/interestFeed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,24 @@ import { DashboardWidgetContent } from './';

type InterestBill = RouterOutputs['user']['interestLegislation'][number];

function matchedSummary(bill: InterestBill): string {
const headings = Object.values(bill.matched_headings ?? {});
if (headings.length > 0) {
const display = headings.slice(0, 2).join(', ');
const extra = headings.length > 2 ? ` +${headings.length - 2}` : '';
return `${display}${extra}`;
}
const idents = bill.matched_idents ?? [];
if (idents.length > 0) {
const slugs = idents
.slice(0, 2)
.map((id: string) => id.split('/').slice(3).join('/'));
const extra = idents.length > 2 ? ` +${idents.length - 2}` : '';
return `${slugs.join(', ')}${extra}`;
}
return '';
}

export function InterestFeed() {
const { data: session } = useSession();
const { data, isLoading, isError } = api.user.interestLegislation.useQuery(
Expand Down Expand Up @@ -76,40 +94,66 @@ export function InterestFeed() {
>
{data && (
<List dense>
{data.slice(0, 8).map((bill: InterestBill) => (
<ListItem
disablePadding
key={bill.legislation_id}
>
<ListItemButton>
<Link
href={`/congress/bills/${bill.legislation_id}`}
style={{
width: '100%',
display: 'block',
}}
>
<Box
sx={{
display: 'flex',
flexDirection: 'column',
{data.slice(0, 8).map((bill: InterestBill) => {
const summary = matchedSummary(bill);
return (
<ListItem
disablePadding
key={bill.legislation_id}
>
<ListItemButton>
<Link
href={`/congress/bills/${bill.legislation_id}`}
style={{
width: '100%',
display: 'block',
}}
>
<Typography color='primary'>
{bill.title}
</Typography>
<Typography variant='caption'>
{`${bill.session_number}th · `}
{bill.chamber === 'house'
? 'H.R.'
: 'S.'}
{` #${bill.number}`}
</Typography>
</Box>
</Link>
</ListItemButton>
</ListItem>
))}
<Box
sx={{
display: 'flex',
flexDirection: 'column',
}}
>
<Typography color='primary'>
{bill.title}
</Typography>
<Box
sx={{
display: 'flex',
alignItems: 'center',
gap: 1,
}}
>
<Typography variant='caption'>
{`${bill.session_number}th · `}
{bill.chamber === 'house'
? 'H.R.'
: 'S.'}
{` #${bill.number}`}
</Typography>
{summary && (
<Typography
color='textSecondary'
sx={{
overflow: 'hidden',
textOverflow:
'ellipsis',
whiteSpace:
'nowrap',
}}
variant='caption'
>
· {summary}
</Typography>
)}
</Box>
</Box>
</Link>
</ListItemButton>
</ListItem>
);
})}
</List>
)}
</DashboardWidgetContent>
Expand Down
56 changes: 52 additions & 4 deletions hillstack/src/app/congress/bills/[billId]/interestBadge.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
'use client';

import TrackChangesIcon from '@mui/icons-material/TrackChanges';
import { Chip, Tooltip } from '@mui/material';
import { Box, Chip, Tooltip, Typography } from '@mui/material';
import { useSession } from 'next-auth/react';
import { api } from '~/trpc/react';

function truncateInterest(text: string, maxLen = 60): string {
if (text.length <= maxLen) return text;
return `${text.slice(0, maxLen).trimEnd()}…`;
}

export function InterestBadge({ legislationId }: { legislationId: number }) {
const { data: session } = useSession();

Expand All @@ -15,10 +20,53 @@ export function InterestBadge({ legislationId }: { legislationId: number }) {

if (!session || !data?.matches) return null;

const hasHeadings = Object.keys(data.matchedHeadings).length > 0;
const interestLabel = data.interestText
? truncateInterest(data.interestText)
: '';

const tooltipContent = (
<Box sx={{ maxWidth: 360 }}>
{interestLabel && (
<Typography sx={{ mb: 0.5 }} variant='caption'>
Related to your interest in "{interestLabel}"
</Typography>
)}
{hasHeadings ? (
<Box component='ul' sx={{ m: 0, pl: 2 }}>
{data.matchedIdents.slice(0, 5).map((ident: string) => {
const heading = data.matchedHeadings[ident];
const slug = ident.split('/').slice(3).join('/');
return (
<li key={ident}>
<Typography variant='caption'>
{heading
? `${slug} — ${heading}`
: slug}
</Typography>
</li>
);
})}
{data.matchedIdents.length > 5 && (
<li>
<Typography color='textSecondary' variant='caption'>
+{data.matchedIdents.length - 5} more
</Typography>
</li>
)}
</Box>
) : (
<Typography variant='caption'>
Touches: {data.matchedIdents.slice(0, 3).join(', ')}
{data.matchedIdents.length > 3 &&
` +${data.matchedIdents.length - 3} more`}
</Typography>
)}
</Box>
);

return (
<Tooltip
title={`Touches your interest areas: ${data.matchedIdents.join(', ')}`}
>
<Tooltip title={tooltipContent}>
<Chip
color='success'
icon={<TrackChangesIcon />}
Expand Down
30 changes: 28 additions & 2 deletions hillstack/src/app/user/interests/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ export default function InterestsPage() {
},
});

const sectionHeadings: Record<string, string> =
interest?.sectionHeadings ?? {};

const rawMatches: MatchItem[] = (
interest?.user_interest_usc_content ?? []
).map((m) => ({
Expand Down Expand Up @@ -213,6 +216,12 @@ export default function InterestsPage() {
?.split('/')
.slice(3)
.join('/') ?? '';
const heading =
match.usc_ident
? sectionHeadings[
match.usc_ident
]
: undefined;
return (
<Box
key={
Expand Down Expand Up @@ -256,15 +265,32 @@ export default function InterestsPage() {
)}
</IconButton>
</Tooltip>
<Typography variant='body2'>
<Typography
sx={{ fontFamily: 'monospace', flexShrink: 0 }}
variant='body2'
>
{sectionSlug}
</Typography>
{heading && (
<Typography
color='textSecondary'
sx={{
ml: 1,
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
}}
variant='body2'
>
— {heading}
</Typography>
)}
{match.match_source ===
'manual' && (
<Chip
label='manual'
size='small'
sx={{ ml: 1 }}
sx={{ ml: 1, flexShrink: 0 }}
variant='outlined'
/>
)}
Expand Down
Loading