Skip to content

Commit

Permalink
Merge pull request #32 from Blue-Net-Reflections-LLC/develop
Browse files Browse the repository at this point in the history
v0.0.5
  • Loading branch information
hreid3 authored Jan 31, 2025
2 parents debbf43 + 4393b00 commit 0b573c8
Show file tree
Hide file tree
Showing 30 changed files with 1,789 additions and 98 deletions.
51 changes: 51 additions & 0 deletions app/[state]/bill/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import SponsorList from './SponsorList';
import RollCallVotes from './RollCallVotes';
import BillAnalysis from './BillAnalysis';
import { Footer } from "@/app/components/layout/Footer";
import { Metadata } from 'next'
import { STATE_NAMES } from '@/app/constants/states';

export const revalidate = 3600; // Revalidate every hour

Expand Down Expand Up @@ -114,6 +116,55 @@ interface BillAnalysis {
}>;
}

interface Props {
params: { state: string; id: string }
}

export async function generateMetadata({ params }: Props): Promise<Metadata> {
const stateCode = params.state.toUpperCase();
const bill = await getBill(stateCode, params.id);

if (!bill) {
return {
title: 'Bill Not Found - LegiEquity',
description: 'The requested bill could not be found.',
}
}

const stateName = STATE_NAMES[stateCode] || stateCode;
const title = `${bill.bill_number}${bill.title !== bill.description ? `: ${bill.title}` : ''}`;
const description = bill.description.length > 200
? bill.description.substring(0, 197) + '...'
: bill.description;

return {
title: `${title} - ${stateName} Legislature - LegiEquity`,
description,
openGraph: {
title: `${title} - ${stateName} Legislature`,
description,
url: `https://legiequity.us/${params.state.toLowerCase()}/bill/${params.id}`,
siteName: 'LegiEquity',
images: [
{
url: `https://legiequity.us/api/og/bill?state=${stateCode}&id=${params.id}`,
width: 1200,
height: 630,
alt: `${bill.bill_number} - ${stateName} Legislature`,
},
],
locale: 'en_US',
type: 'article',
},
twitter: {
card: 'summary_large_image',
title: `${title} - ${stateName} Legislature`,
description,
images: [`https://legiequity.us/api/og/bill?state=${stateCode}&id=${params.id}`],
},
}
}

async function getBillDocuments(billId: string): Promise<BillDocument[]> {
const [texts, supplements] = await Promise.all([
// Get bill texts
Expand Down
39 changes: 39 additions & 0 deletions app/[state]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Metadata } from 'next'
import db from "@/lib/db";
import { BillList } from "@/app/components/BillList";
import Pagination from "@/app/components/Pagination";
Expand All @@ -7,6 +8,44 @@ import { Footer } from "@/app/components/layout/Footer";
import { BillFiltersWrapper } from "@/app/components/filters/BillFiltersWrapper";
import type { BillFilters as BillFiltersType, PartyType } from "@/app/types/filters";
import { CheckCircle, AlertCircle, MinusCircle } from "lucide-react";
import { STATE_NAMES } from '@/app/constants/states';

type Props = {
params: { state: string }
searchParams: { [key: string]: string | string[] | undefined }
}

export async function generateMetadata({ params }: Props): Promise<Metadata> {
const stateCode = params.state.toUpperCase()
const stateName = STATE_NAMES[stateCode] || stateCode

return {
title: `${stateName} Bills - LegiEquity`,
description: `Analyze the demographic impact of ${stateName} legislation. View bills and their effects on age, disability, gender, race, and religious groups.`,
openGraph: {
title: `${stateName} Legislative Analysis - LegiEquity`,
description: `Analyze the demographic impact of ${stateName} legislation. View bills and their effects on age, disability, gender, race, and religious groups.`,
url: `https://legiequity.us/${params.state.toLowerCase()}`,
siteName: 'LegiEquity',
images: [
{
url: `https://legiequity.us/api/og?state=${stateCode}`, // You'll need to create this API route
width: 1200,
height: 630,
alt: `${stateName} Legislative Analysis`,
},
],
locale: 'en_US',
type: 'website',
},
twitter: {
card: 'summary_large_image',
title: `${stateName} Legislative Analysis - LegiEquity`,
description: `Analyze the demographic impact of ${stateName} legislation. View bills and their effects on age, disability, gender, race, and religious groups.`,
images: [`https://legiequity.us/api/og?state=${stateCode}`],
},
}
}

async function getBills(
stateCode: string,
Expand Down
29 changes: 26 additions & 3 deletions app/about/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
import { Footer } from "@/app/components/layout/Footer";
import { AuroraBackground } from "@/app/components/ui/aurora-background";
import { Metadata } from 'next'

export const metadata: Metadata = {
title: 'About LegiEquity',
description: 'Learn about our mission to analyze legislative impact on demographic equity using AI',
openGraph: {
title: 'About LegiEquity',
description: 'Learn about our mission to analyze legislative impact on demographic equity using AI',
images: [{
url: '/api/og/static?page=about',
width: 1200,
height: 630,
alt: 'About LegiEquity'
}]
},
twitter: {
card: 'summary_large_image',
title: 'About LegiEquity',
description: 'Learn about our mission to analyze legislative impact on demographic equity using AI',
images: ['/api/og/static?page=about'],
}
}

export default function AboutPage() {
return (
Expand All @@ -21,10 +43,11 @@ export default function AboutPage() {
<div className="mb-12">
<h2 className="text-3xl font-bold mb-6 text-zinc-900 dark:text-white">Our Vision</h2>
<p className="text-lg leading-relaxed text-zinc-700 dark:text-zinc-300">
VoterAI represents a groundbreaking collaboration between VoterAI and Bluenetreflection,
LegiEquity represents a groundbreaking collaboration between VoterAI and Bluenetreflection,
dedicated to revolutionizing how we understand and interact with legislative processes.
Through advanced AI analysis, we&apos;re making complex legislative information accessible and
meaningful to everyone.

</p>
</div>

Expand Down Expand Up @@ -74,8 +97,8 @@ export default function AboutPage() {
</div>

<div className="bg-gradient-to-r from-blue-50 to-purple-50 dark:from-blue-950/30 dark:to-purple-950/30 p-8 rounded-lg">
<h2 className="text-3xl font-bold mb-6">Upcoming Blog</h2>
<p className="text-lg leading-relaxed">
<h2 className="text-3xl font-bold mb-6 text-zinc-900 dark:text-white">Upcoming Blog</h2>
<p className="text-lg leading-relaxed text-zinc-700 dark:text-zinc-300">
We&apos;re evolving our platform to include in-depth analysis of bills that have severe impacts across the nation.
Our upcoming blog will feature:
</p>
Expand Down
31 changes: 31 additions & 0 deletions app/api/bills/[id]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { NextResponse } from 'next/server'
import db from "@/lib/db";

export async function GET(
request: Request,
{ params }: { params: { id: string } }
) {
try {
const [bill] = await db`
SELECT
bill_number,
title,
description,
state_abbr,
state_name,
status_desc,
current_body_name
FROM lsv_bill
WHERE bill_id = ${params.id}
`

if (!bill) {
return new NextResponse('Bill not found', { status: 404 })
}

return NextResponse.json(bill)
} catch (error) {
console.error('Error fetching bill:', error)
return new NextResponse('Internal Server Error', { status: 500 })
}
}
142 changes: 142 additions & 0 deletions app/api/og/bill/route.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import { ImageResponse } from '@vercel/og'
import { NextRequest } from 'next/server'
import { STATE_NAMES } from '@/app/constants/states';

export const runtime = 'edge'

interface BillData {
bill_number: string;
title: string;
description: string;
state_abbr: string;
state_name: string;
status_desc: string;
current_body_name: string;
}

async function getBill(billId: string): Promise<BillData> {
const baseUrl = process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'
const response = await fetch(`${baseUrl}/api/bills/${billId}`)
if (!response.ok) {
throw new Error('Failed to fetch bill data')
}
return response.json()
}

export async function GET(req: NextRequest) {
try {
const { searchParams } = new URL(req.url)
const stateCode = searchParams.get('state')?.toUpperCase()
const billId = searchParams.get('id')

// Handle missing parameters
if (!stateCode || !billId) {
return new Response('Missing required parameters', { status: 400 })
}

// Get bill data
const bill = await getBill(billId)
if (!bill) {
return new Response('Bill not found', { status: 404 })
}

// Get state name
const stateName = STATE_NAMES[stateCode] || stateCode

// Format title
const title = bill.title !== bill.description
? `${bill.bill_number}: ${bill.title}`
: bill.bill_number

// Truncate description if needed
const description = bill.description.length > 120
? bill.description.substring(0, 117) + '...'
: bill.description

return new ImageResponse(
(
<div
style={{
height: '100%',
width: '100%',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#030712',
padding: '40px 80px',
gap: '40px',
}}
>
{/* Header with state icon and logo */}
<div
style={{
width: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
gap: '24px',
}}
>
<img
src={`https://legiequity.us/images/states/${stateCode.toLowerCase()}.svg`}
alt={stateName}
width={80}
height={80}
/>
<div
style={{
display: 'flex',
alignItems: 'center',
gap: '16px',
}}
>
<svg width="48" height="48" viewBox="0 0 24 24" fill="none">
<path d="M12 3L20 7V17L12 21L4 17V7L12 3Z" stroke="white" strokeWidth="2" />
</svg>
<span
style={{
fontSize: 48,
color: 'white',
fontWeight: 700,
}}
>
LegiEquity
</span>
</div>
</div>

{/* Content */}
<div
style={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
gap: '20px',
width: '100%',
}}
>
<span style={{ fontSize: 32, color: 'white', fontWeight: 600, textAlign: 'center' }}>
{title}
</span>
<span style={{ fontSize: 20, color: '#94a3b8', textAlign: 'center' }}>
{description}
</span>
<span style={{ fontSize: 16, color: '#64748b', textAlign: 'center' }}>
{stateName} Legislature • {bill.current_body_name}{bill.status_desc}
</span>
</div>
</div>
),
{
width: 1200,
height: 630,
},
)
} catch (e: unknown) {
console.log(`${e instanceof Error ? e.message : 'Unknown error'}`)
return new Response(`Failed to generate the image`, {
status: 500,
})
}
}
Loading

0 comments on commit 0b573c8

Please sign in to comment.