2025-03-25 03:52:30 -04:00

311 lines
13 KiB
TypeScript

"use client"
import { useState } from "react"
import Link from "next/link"
import { ArrowRight, ArrowUpDown, Download, FileText, Filter, Search, SortAsc, SortDesc } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"
import { Badge } from "@/components/ui/badge"
import { Separator } from "@/components/ui/separator"
import { Input } from "@/components/ui/input"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
// Mock data for resolutions
const mockResolutions = [
{
id: 12,
title: "Education and Community Health Improvements",
description: "A comprehensive set of recommendations for improving education access and community health services",
date: "2024-02-15",
contributions: 8,
categories: ["Education", "Healthcare"],
status: "active",
},
{
id: 11,
title: "Environmental Protection and Green Spaces",
description: "Recommendations for preserving and expanding green spaces and environmental protections",
date: "2024-01-10",
contributions: 6,
categories: ["Environmental Policy"],
status: "active",
},
{
id: 10,
title: "Public Transportation and Infrastructure",
description: "Proposals for improving public transportation access and infrastructure maintenance",
date: "2023-12-05",
contributions: 7,
categories: ["Infrastructure"],
status: "archived",
},
]
// Add state for search, filter, and sort
export default function ResolutionsPage() {
const [searchQuery, setSearchQuery] = useState("")
const [categoryFilter, setCategoryFilter] = useState("all")
const [statusFilter, setStatusFilter] = useState("all")
const [sortOrder, setSortOrder] = useState<"asc" | "desc">("desc")
const [sortBy, setSortBy] = useState<"contributions" | "date">("date")
// Filter and sort the resolutions
const filteredResolutions = mockResolutions.filter((resolution) => {
// Filter by search query
if (
searchQuery &&
!resolution.title.toLowerCase().includes(searchQuery.toLowerCase()) &&
!resolution.description.toLowerCase().includes(searchQuery.toLowerCase())
)
return false
// Filter by category
if (categoryFilter !== "all" && !resolution.categories.includes(categoryFilter)) return false
// Filter by status
if (statusFilter !== "all" && resolution.status !== statusFilter) return false
return true
})
// Sort the filtered resolutions
const sortedResolutions = [...filteredResolutions].sort((a, b) => {
if (sortBy === "contributions") {
return sortOrder === "desc" ? b.contributions - a.contributions : a.contributions - b.contributions
} else {
const dateA = new Date(a.date).getTime()
const dateB = new Date(b.date).getTime()
return sortOrder === "desc" ? dateB - dateA : dateA - dateB
}
})
// Group resolutions by status
const activeResolutions = sortedResolutions.filter((r) => r.status === "active")
const archivedResolutions = sortedResolutions.filter((r) => r.status === "archived")
// Add the search, filter, and sort UI
return (
<div className="container mx-auto px-4 py-8">
<div className="mb-8">
<h1 className="text-3xl font-bold">Resolutions</h1>
<p className="mt-2 text-muted-foreground">
Final policy recommendations compiled from validated community contributions.
</p>
</div>
{/* Filters and Search */}
<div className="mb-6 flex flex-col gap-4 md:flex-row md:items-center md:justify-between">
<div className="relative w-full md:w-72">
<Search className="absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground" />
<Input
placeholder="Search resolutions..."
className="pl-8"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
/>
</div>
<div className="flex flex-col gap-4 sm:flex-row">
<Select value={categoryFilter} onValueChange={setCategoryFilter}>
<SelectTrigger className="w-full sm:w-[180px]">
<Filter className="mr-2 h-4 w-4" />
<SelectValue placeholder="Filter by category" />
</SelectTrigger>
<SelectContent>
<SelectItem value="all">All Categories</SelectItem>
<SelectItem value="Education">Education</SelectItem>
<SelectItem value="Healthcare">Healthcare</SelectItem>
<SelectItem value="Environmental Policy">Environmental</SelectItem>
<SelectItem value="Infrastructure">Infrastructure</SelectItem>
</SelectContent>
</Select>
<Select value={statusFilter} onValueChange={setStatusFilter}>
<SelectTrigger className="w-full sm:w-[180px]">
<SelectValue placeholder="Filter by status" />
</SelectTrigger>
<SelectContent>
<SelectItem value="all">All Statuses</SelectItem>
<SelectItem value="active">Active</SelectItem>
<SelectItem value="archived">Archived</SelectItem>
</SelectContent>
</Select>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" className="flex items-center gap-2">
<ArrowUpDown className="h-4 w-4" />
Sort by {sortBy === "contributions" ? "Contributions" : "Date"}
{sortOrder === "desc" ? <SortDesc className="ml-1 h-4 w-4" /> : <SortAsc className="ml-1 h-4 w-4" />}
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuLabel>Sort by</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem onClick={() => setSortBy("contributions")}>
Contributions {sortBy === "contributions" && "✓"}
</DropdownMenuItem>
<DropdownMenuItem onClick={() => setSortBy("date")}>Date {sortBy === "date" && "✓"}</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem onClick={() => setSortOrder(sortOrder === "desc" ? "asc" : "desc")}>
{sortOrder === "desc" ? "Ascending" : "Descending"}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
</div>
{filteredResolutions.length === 0 ? (
<div className="mt-12 text-center">
<p className="text-lg font-medium">No resolutions match your filters</p>
<p className="mt-2 text-muted-foreground">Try adjusting your search or filters</p>
<Button
variant="outline"
className="mt-4"
onClick={() => {
setSearchQuery("")
setCategoryFilter("all")
setStatusFilter("all")
}}
>
Clear All Filters
</Button>
</div>
) : (
<>
{statusFilter !== "archived" && activeResolutions.length > 0 && (
<>
<div className="mb-8">
<h2 className="text-xl font-semibold">Active Resolutions</h2>
<p className="text-sm text-muted-foreground">
Current resolutions available for policymakers and the public
</p>
</div>
<div className="grid grid-cols-1 gap-6 md:grid-cols-2">
{activeResolutions.map((resolution) => (
<Card key={resolution.id}>
<CardHeader>
<div className="flex items-start justify-between">
<div>
<CardTitle className="flex items-center gap-2">
<FileText className="h-5 w-5 text-primary" />
Resolution #{resolution.id}
</CardTitle>
<CardDescription className="mt-1">{resolution.title}</CardDescription>
</div>
<Badge>Active</Badge>
</div>
</CardHeader>
<CardContent>
<p className="text-sm text-muted-foreground">{resolution.description}</p>
<div className="mt-4 grid grid-cols-2 gap-4 text-sm">
<div>
<p className="font-medium">Published</p>
<p className="text-muted-foreground">{new Date(resolution.date).toLocaleDateString()}</p>
</div>
<div>
<p className="font-medium">Contributions</p>
<p className="text-muted-foreground">{resolution.contributions} included</p>
</div>
</div>
<div className="mt-4">
<p className="text-sm font-medium">Categories</p>
<div className="mt-2 flex flex-wrap gap-2">
{resolution.categories.map((category) => (
<Badge key={category} variant="outline">
{category}
</Badge>
))}
</div>
</div>
</CardContent>
<CardFooter className="flex flex-col gap-4 sm:flex-row">
<Button variant="outline" className="w-full sm:w-auto" asChild>
<Link href={`/resolutions/${resolution.id}`}>
View Details
<ArrowRight className="ml-2 h-4 w-4" />
</Link>
</Button>
<Button className="w-full sm:w-auto">
<Download className="mr-2 h-4 w-4" />
Download PDF
</Button>
</CardFooter>
</Card>
))}
</div>
</>
)}
{statusFilter !== "active" && archivedResolutions.length > 0 && (
<>
<Separator className="my-8" />
<div className="mb-8">
<h2 className="text-xl font-semibold">Archive</h2>
<p className="text-sm text-muted-foreground">
Past resolutions that have been delivered to policymakers
</p>
</div>
<div className="grid grid-cols-1 gap-6 md:grid-cols-2">
{archivedResolutions.map((resolution) => (
<Card key={resolution.id} className="opacity-80">
<CardHeader>
<div className="flex items-start justify-between">
<div>
<CardTitle className="flex items-center gap-2">
<FileText className="h-5 w-5" />
Resolution #{resolution.id}
</CardTitle>
<CardDescription className="mt-1">{resolution.title}</CardDescription>
</div>
<Badge variant="outline">Archived</Badge>
</div>
</CardHeader>
<CardContent>
<p className="text-sm text-muted-foreground">{resolution.description}</p>
<div className="mt-4 grid grid-cols-2 gap-4 text-sm">
<div>
<p className="font-medium">Published</p>
<p className="text-muted-foreground">{new Date(resolution.date).toLocaleDateString()}</p>
</div>
<div>
<p className="font-medium">Contributions</p>
<p className="text-muted-foreground">{resolution.contributions} included</p>
</div>
</div>
</CardContent>
<CardFooter className="flex flex-col gap-4 sm:flex-row">
<Button variant="outline" className="w-full sm:w-auto" asChild>
<Link href={`/resolutions/${resolution.id}`}>
View Details
<ArrowRight className="ml-2 h-4 w-4" />
</Link>
</Button>
<Button variant="secondary" className="w-full sm:w-auto">
<Download className="mr-2 h-4 w-4" />
Download PDF
</Button>
</CardFooter>
</Card>
))}
</div>
</>
)}
</>
)}
</div>
)
}