Skip to content

Commit

Permalink
Merge pull request #18 from codeforpakistan/pehchan-integration
Browse files Browse the repository at this point in the history
Pehchan integration
  • Loading branch information
aliirz authored Dec 3, 2024
2 parents 52db6bf + 6ea8d83 commit 94445f6
Show file tree
Hide file tree
Showing 44 changed files with 5,508 additions and 379 deletions.
29 changes: 29 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Build Check

on:
push:
branches:
- main
pull_request:
branches:
- main

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Build project
run: npm run build
16 changes: 8 additions & 8 deletions app/about/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@ import { ExternalLink } from "lucide-react"

export default function AboutPage() {
return (
<div className="container mx-auto py-8 space-y-8">
<div className="container mx-auto space-y-8 py-8">
{/* Hero Section */}
<div className="relative h-[400px] rounded-lg overflow-hidden">
<div className="relative h-[400px] overflow-hidden rounded-lg">
<div className="absolute inset-0">
<img
src="parliament.jpg"
alt="Pakistan Parliament"
className="w-full h-full object-cover"
className="size-full object-cover"
/>
<div className="absolute inset-0 bg-gradient-to-b from-black/70 via-black/50 to-black/70" />
</div>
<div className="relative z-10 h-full flex flex-col items-center justify-center text-white p-6 text-center">
<h1 className="scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl mb-4">
<div className="relative z-10 flex h-full flex-col items-center justify-center p-6 text-center text-white">
<h1 className="mb-4 scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl">
Meet Numainda
</h1>
<p className="text-xl text-white/80">
Expand Down Expand Up @@ -69,11 +69,11 @@ export default function AboutPage() {
<CardHeader>
<CardTitle>Our Story in the Media</CardTitle>
</CardHeader>
<CardContent className="flex flex-col md:flex-row gap-6 items-center">
<CardContent className="flex flex-col items-center gap-6 md:flex-row">
<img
src="https://codeforpakistan.org/sites/default/files/cfp_logotype_h.png"
alt="Code for Pakistan Logo"
className="w-24 h-24 object-contain"
className="size-24 object-contain"
/>
<div className="space-y-4">
<h3 className="text-2xl font-semibold">Say Hello to My New Friend</h3>
Expand All @@ -89,7 +89,7 @@ export default function AboutPage() {
className="flex items-center gap-2"
>
Read on Code for Pakistan
<ExternalLink className="h-4 w-4" />
<ExternalLink className="size-4" />
</a>
</Button>
</div>
Expand Down
23 changes: 20 additions & 3 deletions app/admin/upload/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export default function UploadPage() {
const [error, setError] = useState('');
const [loading, setLoading] = useState(false);
const [message, setMessage] = useState('');
const [documentType, setDocumentType] = useState<string>('');

const checkPassword = async (inputPassword: string) => {
try {
Expand Down Expand Up @@ -50,7 +51,7 @@ export default function UploadPage() {
if (!isAuthorized) {
return (
<div className="container max-w-md py-8">
<h1 className="text-2xl font-bold mb-8">Admin Access</h1>
<h1 className="mb-8 text-2xl font-bold">Admin Access</h1>
<div className="space-y-4">
<div className="space-y-2">
<Label htmlFor="password">Password</Label>
Expand Down Expand Up @@ -82,7 +83,7 @@ export default function UploadPage() {

return (
<div className="container max-w-2xl py-8">
<h1 className="text-2xl font-bold mb-8">Upload Document</h1>
<h1 className="mb-8 text-2xl font-bold">Upload Document</h1>

<form onSubmit={handleSubmit} className="space-y-6">
<div className="space-y-2">
Expand All @@ -92,7 +93,11 @@ export default function UploadPage() {

<div className="space-y-2">
<Label htmlFor="type">Document Type</Label>
<Select name="type" required>
<Select
name="type"
required
onValueChange={(value) => setDocumentType(value)}
>
<SelectTrigger>
<SelectValue placeholder="Select document type" />
</SelectTrigger>
Expand All @@ -104,6 +109,18 @@ export default function UploadPage() {
</Select>
</div>

{documentType === 'parliamentary_bulletin' && (
<div className="space-y-2">
<Label htmlFor="date">Bulletin Date</Label>
<Input
id="date"
name="date"
type="date"
required={documentType === 'parliamentary_bulletin'}
/>
</div>
)}

<div className="space-y-2">
<Label htmlFor="file">PDF File</Label>
<Input id="file" name="file" type="file" accept=".pdf" required />
Expand Down
31 changes: 31 additions & 0 deletions app/api/auth/userinfo/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { NextResponse } from "next/server"

export async function GET(request: Request) {
const authHeader = request.headers.get('Authorization')

if (!authHeader) {
return NextResponse.json({ error: 'No authorization header' }, { status: 401 })
}

try {
const response = await fetch(`${process.env.NEXT_PUBLIC_PEHCHAN_URL}/api/auth/userinfo`, {
headers: {
'Authorization': authHeader
}
})

if (!response.ok) {
throw new Error('Failed to fetch user info')
}

const data = await response.json()
console.log('Pehchan userinfo response:', data)
return NextResponse.json(data)
} catch (error) {
console.error('User info error:', error)
return NextResponse.json(
{ error: 'Failed to fetch user info' },
{ status: 500 }
)
}
}
95 changes: 95 additions & 0 deletions app/api/chat/threads/[id]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { db } from '@/lib/db'
import { chatThreads } from '@/lib/db/schema/chat-threads'
import { eq, and } from 'drizzle-orm'
import { NextResponse } from 'next/server'

export async function GET(
request: Request,
{ params }: { params: { id: string } }
) {
const { searchParams } = new URL(request.url)
const pehchanId = searchParams.get('pehchan_id')

if (!pehchanId) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}

try {
const [thread] = await db
.select()
.from(chatThreads)
.where(
and(
eq(chatThreads.id, parseInt(params.id)),
eq(chatThreads.pehchanId, pehchanId)
)
)

return NextResponse.json(thread)
} catch (error) {
return NextResponse.json({ error: 'Failed to fetch thread' }, { status: 500 })
}
}

export async function PATCH(
request: Request,
{ params }: { params: { id: string } }
) {
const { messages, title, pehchanId } = await request.json()

if (!pehchanId) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}

try {
const [thread] = await db
.update(chatThreads)
.set({
messages,
title,
updatedAt: new Date()
})
.where(
and(
eq(chatThreads.id, parseInt(params.id)),
eq(chatThreads.pehchanId, pehchanId)
)
)
.returning()

return NextResponse.json(thread)
} catch (error) {
return NextResponse.json({ error: 'Failed to update thread' }, { status: 500 })
}
}

export async function DELETE(
request: Request,
{ params }: { params: { id: string } }
) {
const { pehchanId } = await request.json()

if (!pehchanId) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}

try {
const [deletedThread] = await db
.delete(chatThreads)
.where(
and(
eq(chatThreads.id, parseInt(params.id)),
eq(chatThreads.pehchanId, pehchanId)
)
)
.returning()

return NextResponse.json(deletedThread)
} catch (error) {
console.error('Error deleting thread:', error)
return NextResponse.json(
{ error: 'Failed to delete thread' },
{ status: 500 }
)
}
}
51 changes: 51 additions & 0 deletions app/api/chat/threads/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { db } from '@/lib/db'
import { chatThreads } from '@/lib/db/schema/chat-threads'
import { eq } from 'drizzle-orm'
import { NextResponse } from 'next/server'

export async function GET(request: Request) {
const { searchParams } = new URL(request.url)
const pehchanId = searchParams.get('pehchan_id')

if (!pehchanId) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}

try {
const threads = await db
.select()
.from(chatThreads)
.where(eq(chatThreads.pehchanId, pehchanId))
.orderBy(chatThreads.updatedAt)

return NextResponse.json(threads)
} catch (error) {
return NextResponse.json({ error: 'Failed to fetch threads' }, { status: 500 })
}
}

export async function POST(request: Request) {
const { pehchanId, title = 'New Chat', messages = [] } = await request.json()
console.log('Creating thread:', { pehchanId, title, messages })

if (!pehchanId) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}

try {
const [thread] = await db
.insert(chatThreads)
.values({
pehchanId,
title,
messages
})
.returning()

console.log('Created thread:', thread)
return NextResponse.json(thread)
} catch (error) {
console.error('Failed to create thread:', error)
return NextResponse.json({ error: 'Failed to create thread' }, { status: 500 })
}
}
Loading

0 comments on commit 94445f6

Please sign in to comment.