diff --git a/README.md b/README.md deleted file mode 100644 index 482076f4..00000000 --- a/README.md +++ /dev/null @@ -1 +0,0 @@ -# DevCreateBuildTest diff --git a/submission/T054_JUST_US/README.md b/submission/T054_JUST_US/README.md new file mode 100644 index 00000000..09c230c8 --- /dev/null +++ b/submission/T054_JUST_US/README.md @@ -0,0 +1 @@ +# project_sahaara \ No newline at end of file diff --git a/submission/T054_JUST_US/T054_JUST-US.pdf b/submission/T054_JUST_US/T054_JUST-US.pdf new file mode 100644 index 00000000..2f9672ea Binary files /dev/null and b/submission/T054_JUST_US/T054_JUST-US.pdf differ diff --git a/submission/program/.gitignore b/submission/program/.gitignore new file mode 100644 index 00000000..f650315f --- /dev/null +++ b/submission/program/.gitignore @@ -0,0 +1,27 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules + +# next.js +/.next/ +/out/ + +# production +/build + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts \ No newline at end of file diff --git a/submission/program/app/community/loading.tsx b/submission/program/app/community/loading.tsx new file mode 100644 index 00000000..f15322a8 --- /dev/null +++ b/submission/program/app/community/loading.tsx @@ -0,0 +1,3 @@ +export default function Loading() { + return null +} diff --git a/submission/program/app/community/page.tsx b/submission/program/app/community/page.tsx new file mode 100644 index 00000000..a3d39e6d --- /dev/null +++ b/submission/program/app/community/page.tsx @@ -0,0 +1,268 @@ +"use client" + +import { useState, useEffect } from "react" +import Link from "next/link" +import Image from "next/image" +import { Button } from "@/components/ui/button" +import { Card } from "@/components/ui/card" +import { Input } from "@/components/ui/input" +import { Badge } from "@/components/ui/badge" +import { HeartHandshake, Search, Plus, MapPin, Clock, AlertCircle, Package } from "lucide-react" +import { dataStore, type HelpRequest, type InventoryItem } from "@/lib/data-store" +import { RequestForm } from "@/components/request-form" +import { RequestCard } from "@/components/request-card" + +export default function CommunityPortal() { + const [requests, setRequests] = useState([]) + const [inventory, setInventory] = useState([]) + const [searchQuery, setSearchQuery] = useState("") + const [showRequestForm, setShowRequestForm] = useState(false) + const [activeTab, setActiveTab] = useState<"requests" | "resources">("requests") + + useEffect(() => { + setRequests(dataStore.getRequests()) + setInventory(dataStore.getInventory()) + }, []) + + const filteredRequests = requests.filter( + (req) => + req.victimName.toLowerCase().includes(searchQuery.toLowerCase()) || + req.location.toLowerCase().includes(searchQuery.toLowerCase()) || + req.itemsNeeded.some((item) => item.toLowerCase().includes(searchQuery.toLowerCase())), + ) + + const filteredInventory = inventory.filter( + (item) => + item.name.toLowerCase().includes(searchQuery.toLowerCase()) || + item.category.toLowerCase().includes(searchQuery.toLowerCase()) || + item.location.toLowerCase().includes(searchQuery.toLowerCase()), + ) + + const handleRequestSubmit = (request: Omit) => { + const newRequest = dataStore.addRequest(request) + setRequests([newRequest, ...requests]) + setShowRequestForm(false) + } + + const pendingCount = requests.filter((r) => r.status === "pending").length + const criticalCount = requests.filter((r) => r.urgency === "critical" && r.status === "pending").length + + return ( +
+ {/* Header */} +
+
+ +
+ +
+
+ Relief Connect + Community Portal +
+ + + + +
+
+ +
+ {/* Community Portal Hero Banner */} +
+ Community members helping each other during disaster +
+
+

Community Portal

+

Submit your needs and track relief efforts in real-time

+
+
+
+ + {/* Stats Banner */} +
+ +
{requests.length}
+
Total Requests
+
+ +
{pendingCount}
+
Pending Help
+
+ +
{criticalCount}
+
Critical Cases
+
+ +
{inventory.length}
+
Resources Available
+
+
+ + {/* Main Content */} +
+ {/* Left Column - Request Form */} +
+ +
+ +

Need Help?

+
+

+ Submit your request and NGOs in your area will be notified immediately. All requests are tracked in + real-time. +

+ + +
+

Quick Info

+
+
+ +
+
Response Time
+
Average 2-4 hours
+
+
+
+ +
+
Coverage
+
All Punjab districts
+
+
+
+ +
+
Resources
+
{inventory.length} items available
+
+
+
+
+
+
+ + {/* Right Column - Requests & Resources */} +
+ {/* Tabs */} +
+ + +
+ + {/* Search */} +
+ + setSearchQuery(e.target.value)} + className="pl-10 bg-card border-border text-foreground" + /> +
+ + {/* Content */} + {activeTab === "requests" ? ( +
+ {filteredRequests.length === 0 ? ( + + +

No requests found

+
+ ) : ( + filteredRequests.map((request) => ( + + )) + )} +
+ ) : ( +
+ {filteredInventory.length === 0 ? ( + + +

No resources found

+
+ ) : ( + filteredInventory.map((item) => ( + +
+
+
+

{item.name}

+ + {item.category} + +
+
+
+ + + {item.quantity} {item.unit} + +
+
+ + {item.location} +
+
+
+
100 + ? "bg-success/10 text-success" + : item.quantity > 50 + ? "bg-warning/10 text-warning" + : "bg-destructive/10 text-destructive" + }`} + > + {item.quantity > 100 ? "In Stock" : item.quantity > 50 ? "Low Stock" : "Critical"} +
+
+
+ )) + )} +
+ )} +
+
+
+ + {/* Request Form Modal */} + {showRequestForm && setShowRequestForm(false)} onSubmit={handleRequestSubmit} />} +
+ ) +} diff --git a/submission/program/app/disaster-map/page.tsx b/submission/program/app/disaster-map/page.tsx new file mode 100644 index 00000000..cad82549 --- /dev/null +++ b/submission/program/app/disaster-map/page.tsx @@ -0,0 +1,368 @@ +"use client" + +import { useEffect, useState } from "react" +import { Card } from "@/components/ui/card" +import { Badge } from "@/components/ui/badge" +import { Button } from "@/components/ui/button" +import { AlertTriangle, Cloud, Droplets, Wind, Thermometer, MapPin, RefreshCw, ArrowLeft } from "lucide-react" +import Link from "next/link" +import { getWeatherData, getRiskColor, type WeatherData } from "@/lib/weather-data" + +export default function DisasterMapPage() { + const [weatherData, setWeatherData] = useState([]) + const [selectedRegion, setSelectedRegion] = useState(null) + const [lastUpdate, setLastUpdate] = useState(new Date()) + const [isRefreshing, setIsRefreshing] = useState(false) + + // Load weather data + useEffect(() => { + loadWeatherData() + // Auto-refresh every 30 seconds + const interval = setInterval(loadWeatherData, 30000) + return () => clearInterval(interval) + }, []) + + // Load Leaflet dynamically (client-side only) + useEffect(() => { + if (typeof window !== "undefined") { + // Add Leaflet CSS + const link = document.createElement("link") + link.rel = "stylesheet" + link.href = "https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" + document.head.appendChild(link) + + // Load Leaflet JS + const script = document.createElement("script") + script.src = "https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" + script.async = true + script.onload = () => initializeMap() + document.body.appendChild(script) + + return () => { + document.head.removeChild(link) + document.body.removeChild(script) + } + } + }, [weatherData]) + + const loadWeatherData = () => { + const data = getWeatherData() + setWeatherData(data) + setLastUpdate(new Date()) + } + + const handleRefresh = () => { + setIsRefreshing(true) + loadWeatherData() + setTimeout(() => setIsRefreshing(false), 1000) + } + + const initializeMap = () => { + if (typeof window === "undefined" || !window.L || weatherData.length === 0) return + + // Remove existing map if any + const mapContainer = document.getElementById("disaster-map") + if (!mapContainer) return + mapContainer.innerHTML = "" + + // Initialize map centered on India + const map = window.L.map("disaster-map").setView([20.5937, 78.9629], 5) + + // Add OpenStreetMap tiles + window.L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", { + attribution: '© OpenStreetMap contributors', + maxZoom: 18, + }).addTo(map) + + // Add markers for each region + weatherData.forEach((region) => { + const color = getRiskColor(region.riskLevel) + + // Create custom icon + const icon = window.L.divIcon({ + className: "custom-marker", + html: ` +
+ + + +
+ `, + iconSize: [30, 30], + iconAnchor: [15, 15], + }) + + const marker = window.L.marker(region.coordinates, { icon }).addTo(map) + + // Add popup + const popupContent = ` +
+

${region.region}, ${region.state}

+
+ ${region.riskLevel.toUpperCase()} +
+
+
🌡️ Temp: ${region.temperature.toFixed(1)}°C
+
💧 Humidity: ${region.humidity.toFixed(0)}%
+
🌧️ Rainfall: ${region.rainfall.toFixed(1)}mm
+
💨 Wind: ${region.windSpeed.toFixed(1)} km/h
+ ${ + region.disasterType.length > 0 + ? `
⚠️ Risks: ${region.disasterType.join(", ")}
` + : "" + } +
+
+ ` + + marker.bindPopup(popupContent) + + // Click handler + marker.on("click", () => { + setSelectedRegion(region) + }) + }) + } + + const criticalRegions = weatherData.filter((r) => r.riskLevel === "critical") + const highRiskRegions = weatherData.filter((r) => r.riskLevel === "high") + + return ( +
+ {/* Header */} +
+
+
+ + + +
+ + SAHAARA - Disaster Risk Map +
+
+ +
+
+ +
+ {/* Stats Overview */} +
+ +
{criticalRegions.length}
+
Critical Zones
+
+ +
{highRiskRegions.length}
+
High Risk Zones
+
+ +
{weatherData.length}
+
Monitored Regions
+
+ +
+ {lastUpdate.toLocaleTimeString("en-IN", { hour: "2-digit", minute: "2-digit" })} +
+
Last Updated
+
+
+ +
+ {/* Map Section */} +
+ +
+

Real-Time Weather & Risk Map

+
+ + Live Data +
+
+ + {/* Map Container */} +
+ + {/* Legend */} +
+ Risk Levels: +
+
+ Critical +
+
+
+ High +
+
+
+ Moderate +
+
+
+ Low +
+
+ +
+ + {/* Sidebar - Region Details & Alerts */} +
+ {/* Selected Region Details */} + {selectedRegion && ( + +

Selected Region

+
+
+
{selectedRegion.region}
+
{selectedRegion.state}
+
+ + + {selectedRegion.riskLevel.toUpperCase()} RISK + + +
+
+
+ + Temperature +
+ {selectedRegion.temperature.toFixed(1)}°C +
+ +
+
+ + Humidity +
+ {selectedRegion.humidity.toFixed(0)}% +
+ +
+
+ + Rainfall (24h) +
+ {selectedRegion.rainfall.toFixed(1)}mm +
+ +
+
+ + Wind Speed +
+ {selectedRegion.windSpeed.toFixed(1)} km/h +
+
+ + {selectedRegion.disasterType.length > 0 && ( +
+
+ + Active Threats +
+
+ {selectedRegion.disasterType.map((type) => ( + + {type} + + ))} +
+
+ )} +
+
+ )} + + {/* Critical Alerts */} + +
+ +

Critical Alerts

+
+ +
+ {criticalRegions.length === 0 ? ( +

No critical alerts at this time

+ ) : ( + criticalRegions.map((region) => ( +
setSelectedRegion(region)} + > +
{region.region}
+
+ {region.disasterType.join(", ") || "Extreme conditions"} +
+
+ )) + )} +
+
+ + {/* All Regions List */} + +

All Monitored Regions

+
+ {weatherData.map((region) => ( +
setSelectedRegion(region)} + > +
+ {region.region} +
+
+
{region.state}
+
+ {region.temperature.toFixed(0)}°C • {region.humidity.toFixed(0)}% • {region.rainfall.toFixed(0)} + mm +
+
+ ))} +
+ +
+
+
+
+ ) +} + +// Extend Window interface for Leaflet +declare global { + interface Window { + L: any + } +} diff --git a/submission/program/app/globals.css b/submission/program/app/globals.css new file mode 100644 index 00000000..77004f9e --- /dev/null +++ b/submission/program/app/globals.css @@ -0,0 +1,144 @@ +@import "tailwindcss"; +@import "tw-animate-css"; + +@custom-variant dark (&:is(.dark *)); + +:root { + /* Updated theme for disaster relief platform with dark background and amber accents */ + --background: oklch(0.15 0.01 240); + --foreground: oklch(0.98 0 0); + --card: oklch(0.18 0.01 240); + --card-foreground: oklch(0.98 0 0); + --popover: oklch(0.18 0.01 240); + --popover-foreground: oklch(0.98 0 0); + --primary: oklch(0.75 0.15 75); + --primary-foreground: oklch(0.15 0.01 240); + --secondary: oklch(0.25 0.01 240); + --secondary-foreground: oklch(0.98 0 0); + --muted: oklch(0.25 0.01 240); + --muted-foreground: oklch(0.65 0.01 240); + --accent: oklch(0.75 0.15 75); + --accent-foreground: oklch(0.15 0.01 240); + --destructive: oklch(0.55 0.22 25); + --destructive-foreground: oklch(0.98 0 0); + --border: oklch(0.28 0.01 240); + --input: oklch(0.28 0.01 240); + --ring: oklch(0.75 0.15 75); + --chart-1: oklch(0.75 0.15 75); + --chart-2: oklch(0.65 0.18 140); + --chart-3: oklch(0.6 0.2 200); + --chart-4: oklch(0.7 0.18 50); + --chart-5: oklch(0.55 0.2 300); + --radius: 0.5rem; + --sidebar: oklch(0.18 0.01 240); + --sidebar-foreground: oklch(0.98 0 0); + --sidebar-primary: oklch(0.75 0.15 75); + --sidebar-primary-foreground: oklch(0.15 0.01 240); + --sidebar-accent: oklch(0.25 0.01 240); + --sidebar-accent-foreground: oklch(0.98 0 0); + --sidebar-border: oklch(0.28 0.01 240); + --sidebar-ring: oklch(0.75 0.15 75); + --success: oklch(0.65 0.18 140); + --success-foreground: oklch(0.15 0.01 240); + --warning: oklch(0.75 0.15 75); + --warning-foreground: oklch(0.15 0.01 240); + --info: oklch(0.6 0.2 200); + --info-foreground: oklch(0.98 0 0); +} + +.dark { + --background: oklch(0.15 0.01 240); + --foreground: oklch(0.98 0 0); + --card: oklch(0.18 0.01 240); + --card-foreground: oklch(0.98 0 0); + --popover: oklch(0.18 0.01 240); + --popover-foreground: oklch(0.98 0 0); + --primary: oklch(0.75 0.15 75); + --primary-foreground: oklch(0.15 0.01 240); + --secondary: oklch(0.25 0.01 240); + --secondary-foreground: oklch(0.98 0 0); + --muted: oklch(0.25 0.01 240); + --muted-foreground: oklch(0.65 0.01 240); + --accent: oklch(0.75 0.15 75); + --accent-foreground: oklch(0.15 0.01 240); + --destructive: oklch(0.55 0.22 25); + --destructive-foreground: oklch(0.98 0 0); + --border: oklch(0.28 0.01 240); + --input: oklch(0.28 0.01 240); + --ring: oklch(0.75 0.15 75); + --chart-1: oklch(0.75 0.15 75); + --chart-2: oklch(0.65 0.18 140); + --chart-3: oklch(0.6 0.2 200); + --chart-4: oklch(0.7 0.18 50); + --chart-5: oklch(0.55 0.2 300); + --sidebar: oklch(0.18 0.01 240); + --sidebar-foreground: oklch(0.98 0 0); + --sidebar-primary: oklch(0.75 0.15 75); + --sidebar-primary-foreground: oklch(0.15 0.01 240); + --sidebar-accent: oklch(0.25 0.01 240); + --sidebar-accent-foreground: oklch(0.98 0 0); + --sidebar-border: oklch(0.28 0.01 240); + --sidebar-ring: oklch(0.75 0.15 75); + --success: oklch(0.65 0.18 140); + --success-foreground: oklch(0.15 0.01 240); + --warning: oklch(0.75 0.15 75); + --warning-foreground: oklch(0.15 0.01 240); + --info: oklch(0.6 0.2 200); + --info-foreground: oklch(0.98 0 0); +} + +@theme inline { + --font-sans: var(--font-geist-sans); + --font-mono: var(--font-geist-mono); + --color-background: var(--background); + --color-foreground: var(--foreground); + --color-card: var(--card); + --color-card-foreground: var(--card-foreground); + --color-popover: var(--popover); + --color-popover-foreground: var(--popover-foreground); + --color-primary: var(--primary); + --color-primary-foreground: var(--primary-foreground); + --color-secondary: var(--secondary); + --color-secondary-foreground: var(--secondary-foreground); + --color-muted: var(--muted); + --color-muted-foreground: var(--muted-foreground); + --color-accent: var(--accent); + --color-accent-foreground: var(--accent-foreground); + --color-destructive: var(--destructive); + --color-destructive-foreground: var(--destructive-foreground); + --color-border: var(--border); + --color-input: var(--input); + --color-ring: var(--ring); + --color-chart-1: var(--chart-1); + --color-chart-2: var(--chart-2); + --color-chart-3: var(--chart-3); + --color-chart-4: var(--chart-4); + --color-chart-5: var(--chart-5); + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); + --color-sidebar: var(--sidebar); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-ring: var(--sidebar-ring); + --color-success: var(--success); + --color-success-foreground: var(--success-foreground); + --color-warning: var(--warning); + --color-warning-foreground: var(--warning-foreground); + --color-info: var(--info); + --color-info-foreground: var(--info-foreground); +} + +@layer base { + * { + @apply border-border outline-ring/50; + } + body { + @apply bg-background text-foreground; + } +} diff --git a/submission/program/app/layout.tsx b/submission/program/app/layout.tsx new file mode 100644 index 00000000..d697aded --- /dev/null +++ b/submission/program/app/layout.tsx @@ -0,0 +1,28 @@ +import type React from "react" +import type { Metadata } from "next" +import { GeistSans } from "geist/font/sans" +import { GeistMono } from "geist/font/mono" +import { Analytics } from "@vercel/analytics/next" +import { Suspense } from "react" +import "./globals.css" + +export const metadata: Metadata = { + title: "SAHAARA - Disaster Relief Management Platform", + description: "Connecting communities in need with NGOs during disasters across India", + generator: "v0.app", +} + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode +}>) { + return ( + + + {children} + + + + ) +} diff --git a/submission/program/app/ngo/loading.tsx b/submission/program/app/ngo/loading.tsx new file mode 100644 index 00000000..f15322a8 --- /dev/null +++ b/submission/program/app/ngo/loading.tsx @@ -0,0 +1,3 @@ +export default function Loading() { + return null +} diff --git a/submission/program/app/ngo/page.tsx b/submission/program/app/ngo/page.tsx new file mode 100644 index 00000000..a80c19d1 --- /dev/null +++ b/submission/program/app/ngo/page.tsx @@ -0,0 +1,892 @@ +"use client" + +import { useState, useEffect } from "react" +import Link from "next/link" +import Image from "next/image" +import { Button } from "@/components/ui/button" +import { Card } from "@/components/ui/card" +import { Input } from "@/components/ui/input" +import { Badge } from "@/components/ui/badge" +import { + HeartHandshake, + Search, + LayoutDashboard, + Package, + ClipboardList, + Menu, + AlertCircle, + CheckCircle, + Trash2, + LogOut, + User, + Map, +} from "lucide-react" +import { dataStore, type HelpRequest, type InventoryItem } from "@/lib/data-store" +import { authStore, type AuthSession } from "@/lib/auth-store" +import { NGOLogin } from "@/components/ngo-login" +import { RequestCard } from "@/components/request-card" +import { InventoryForm } from "@/components/inventory-form" +import { InventoryUpdateForm } from "@/components/inventory-update-form" +import { getWeatherData, getRiskColor, type WeatherData } from "@/lib/weather-data" + +export default function NGODashboard() { + const [isAuthenticated, setIsAuthenticated] = useState(false) + const [session, setSession] = useState(null) + const [isLoading, setIsLoading] = useState(true) + + const [requests, setRequests] = useState([]) + const [inventory, setInventory] = useState([]) + const [searchQuery, setSearchQuery] = useState("") + const [activeTab, setActiveTab] = useState<"overview" | "requests" | "inventory" | "disaster-map">("overview") + const [sidebarOpen, setSidebarOpen] = useState(false) + const [showInventoryForm, setShowInventoryForm] = useState(false) + const [editingItem, setEditingItem] = useState(null) + const [updatingItem, setUpdatingItem] = useState(null) + const [filterStatus, setFilterStatus] = useState<"all" | "pending" | "claimed" | "fulfilled">("all") + + const [weatherData, setWeatherData] = useState([]) + const [selectedRegion, setSelectedRegion] = useState(null) + + useEffect(() => { + const currentSession = authStore.getSession() + if (currentSession) { + setIsAuthenticated(true) + setSession(currentSession) + } + setIsLoading(false) + }, []) + + useEffect(() => { + if (isAuthenticated) { + setRequests(dataStore.getRequests()) + setInventory(dataStore.getInventory()) + setWeatherData(getWeatherData()) + } + }, [isAuthenticated]) + + useEffect(() => { + if (activeTab === "disaster-map" && typeof window !== "undefined") { + // Add Leaflet CSS if not already added + if (!document.querySelector('link[href*="leaflet.css"]')) { + const link = document.createElement("link") + link.rel = "stylesheet" + link.href = "https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" + document.head.appendChild(link) + } + + // Load Leaflet JS if not already loaded + if (!window.L) { + const script = document.createElement("script") + script.src = "https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" + script.async = true + script.onload = () => setTimeout(initializeMap, 100) + document.body.appendChild(script) + } else { + setTimeout(initializeMap, 100) + } + } + }, [activeTab, weatherData]) + + const initializeMap = () => { + if (typeof window === "undefined" || !window.L || weatherData.length === 0) return + + const mapContainer = document.getElementById("ngo-disaster-map") + if (!mapContainer) return + mapContainer.innerHTML = "" + + const map = window.L.map("ngo-disaster-map").setView([20.5937, 78.9629], 5) + + window.L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", { + attribution: "© OpenStreetMap contributors", + maxZoom: 18, + }).addTo(map) + + weatherData.forEach((region) => { + const color = getRiskColor(region.riskLevel) + const icon = window.L.divIcon({ + className: "custom-marker", + html: ` +
+ + + +
+ `, + iconSize: [30, 30], + iconAnchor: [15, 15], + }) + + const marker = window.L.marker(region.coordinates, { icon }).addTo(map) + + const popupContent = ` +
+

${region.region}, ${region.state}

+
+ ${region.riskLevel.toUpperCase()} +
+
+
🌡️ Temp: ${region.temperature.toFixed(1)}°C
+
💧 Humidity: ${region.humidity.toFixed(0)}%
+
🌧️ Rainfall: ${region.rainfall.toFixed(1)}mm
+
💨 Wind: ${region.windSpeed.toFixed(1)} km/h
+
+
+ ` + + marker.bindPopup(popupContent) + marker.on("click", () => setSelectedRegion(region)) + }) + } + + const handleLoginSuccess = () => { + const currentSession = authStore.getSession() + setSession(currentSession) + setIsAuthenticated(true) + } + + const handleLogout = () => { + authStore.logout() + setIsAuthenticated(false) + setSession(null) + } + + const handleClaimRequest = (id: string) => { + dataStore.updateRequest(id, { + status: "claimed", + claimedBy: session?.organizationName || "Your NGO", + }) + setRequests(dataStore.getRequests()) + } + + const handleFulfillRequest = (id: string) => { + dataStore.updateRequest(id, { + status: "fulfilled", + fulfilledAt: new Date().toISOString(), + }) + setRequests(dataStore.getRequests()) + } + + const handleDeleteRequest = (id: string) => { + dataStore.deleteRequest(id) + setRequests(dataStore.getRequests()) + } + + const handleAddInventory = (item: Omit) => { + dataStore.addInventoryItem(item) + setInventory(dataStore.getInventory()) + setShowInventoryForm(false) + } + + const handleEditInventory = (item: Omit) => { + if (editingItem) { + dataStore.updateInventoryItem(editingItem.id, item) + setInventory(dataStore.getInventory()) + setEditingItem(null) + } + } + + const handleUpdateQuantity = (id: string, newQuantity: number) => { + dataStore.updateInventoryItem(id, { quantity: newQuantity }) + setInventory(dataStore.getInventory()) + setUpdatingItem(null) + } + + const handleDeleteInventory = (id: string) => { + if (confirm("Are you sure you want to delete this item?")) { + dataStore.deleteInventoryItem(id) + setInventory(dataStore.getInventory()) + } + } + + const filteredRequests = requests.filter((req) => { + const matchesSearch = + req.victimName.toLowerCase().includes(searchQuery.toLowerCase()) || + req.location.toLowerCase().includes(searchQuery.toLowerCase()) || + req.itemsNeeded.some((item) => item.toLowerCase().includes(searchQuery.toLowerCase())) + + const matchesStatus = filterStatus === "all" || req.status === filterStatus + + return matchesSearch && matchesStatus + }) + + const pendingRequests = requests.filter((r) => r.status === "pending") + const claimedRequests = requests.filter((r) => r.status === "claimed") + const fulfilledRequests = requests.filter((r) => r.status === "fulfilled") + const criticalRequests = requests.filter((r) => r.urgency === "critical" && r.status === "pending") + + const totalInventoryValue = inventory.reduce((sum, item) => sum + item.quantity, 0) + const lowStockItems = inventory.filter((item) => item.quantity < 100) + + // Calculate critical and high risk regions for the disaster map + const criticalRegions = weatherData.filter((r) => r.riskLevel === "critical") + const highRiskRegions = weatherData.filter((r) => r.riskLevel === "high") + + if (isLoading) { + return ( +
+
+
+ +
+

Loading...

+
+
+ ) + } + + if (!isAuthenticated) { + return + } + + return ( +
+ {/* Header */} +
+
+
+ + +
+ +
+
+ SAHAARA + NGO Dashboard +
+ +
+
+
+ +
+
{session?.organizationName}
+
{session?.email}
+
+
+ + + + +
+
+
+ +
+ {/* Sidebar */} + + + {/* Overlay for mobile */} + {sidebarOpen && ( +
setSidebarOpen(false)} + /> + )} + + {/* Main Content */} +
+ {activeTab === "overview" && ( +
+
+ NGO relief operations and coordination center +
+
+

Dashboard Overview

+

Monitor and coordinate relief efforts in real-time

+
+
+
+ + {/* Stats Grid */} +
+ +
+ Total Requests + +
+
{requests.length}
+
All time
+
+ + +
+ Pending + +
+
{pendingRequests.length}
+
{criticalRequests.length} critical cases
+
+ + +
+ Fulfilled + +
+
{fulfilledRequests.length}
+
+ {requests.length > 0 ? Math.round((fulfilledRequests.length / requests.length) * 100) : 0}% + completion rate +
+
+ + +
+ Inventory Items + +
+
{inventory.length}
+
{totalInventoryValue} total units
+
+
+ + {/* Critical Requests */} + {criticalRequests.length > 0 && ( +
+
+ +

Critical Requests

+ {criticalRequests.length} +
+
+ {criticalRequests.slice(0, 3).map((request) => ( + + ))} +
+
+ )} + + {/* Recent Activity */} +
+

Recent Requests

+
+ {requests.slice(0, 5).map((request) => ( + + ))} +
+
+ + {/* Low Stock Alert */} + {lowStockItems.length > 0 && ( + +
+ +

Low Stock Alert

+
+
+ {lowStockItems.map((item) => ( +
+
+
{item.name}
+
{item.location}
+
+
+
+ {item.quantity} {item.unit} +
+
Low stock
+
+
+ ))} +
+
+ )} +
+ )} + + {activeTab === "requests" && ( +
+
+

Help Requests

+

Manage and respond to community requests

+
+ + {/* Filter Tabs */} +
+ + + + +
+ + {/* Search */} +
+ + setSearchQuery(e.target.value)} + className="pl-10 bg-card border-border text-foreground" + /> +
+ + {/* Requests List */} +
+ {filteredRequests.length === 0 ? ( + + +

No requests found

+
+ ) : ( + filteredRequests.map((request) => ( + + )) + )} +
+
+ )} + + {activeTab === "inventory" && ( +
+
+
+

Inventory Management

+

Track and manage relief supplies

+
+ +
+ + {/* Inventory Stats */} +
+ +
Total Items
+
{inventory.length}
+
+ +
Total Units
+
{totalInventoryValue}
+
+ +
Low Stock Items
+
{lowStockItems.length}
+
+
+ +
+ {inventory.map((item) => ( + +
+
+

{item.name}

+ + {item.category} + +
+
100 + ? "bg-success/10 text-success" + : item.quantity > 50 + ? "bg-warning/10 text-warning" + : "bg-destructive/10 text-destructive" + }`} + > + {item.quantity > 100 ? "In Stock" : item.quantity > 50 ? "Low" : "Critical"} +
+
+
+
+ Quantity + + {item.quantity} {item.unit} + +
+
+ Location + {item.location} +
+
+
+ + + +
+
+ ))} +
+
+ )} + + {activeTab === "disaster-map" && ( +
+
+

Disaster Risk Map

+

Monitor weather conditions and disaster risk zones across India

+
+ + {/* Stats Overview */} +
+ +
{criticalRegions.length}
+
Critical Zones
+
+ +
{highRiskRegions.length}
+
High Risk Zones
+
+ +
{weatherData.length}
+
Monitored Regions
+
+ +
Live
+
Real-time Data
+
+
+ +
+ {/* Map Section */} +
+ +

Interactive Weather Map

+
+
+ Risk Levels: +
+
+ Critical +
+
+
+ High +
+
+
+ Moderate +
+
+
+ Low +
+
+ +
+ + {/* Sidebar - Region Details */} +
+ {selectedRegion && ( + +

Selected Region

+
+
+
{selectedRegion.region}
+
{selectedRegion.state}
+
+ + {selectedRegion.riskLevel.toUpperCase()} RISK + +
+
+ Temperature + + {selectedRegion.temperature.toFixed(1)}°C + +
+
+ Humidity + {selectedRegion.humidity.toFixed(0)}% +
+
+ Rainfall + + {selectedRegion.rainfall.toFixed(1)}mm + +
+
+ Wind Speed + + {selectedRegion.windSpeed.toFixed(1)} km/h + +
+
+
+
+ )} + + {/* Critical Alerts */} + +
+ +

Critical Alerts

+
+
+ {criticalRegions.length === 0 ? ( +

No critical alerts

+ ) : ( + criticalRegions.map((region) => ( +
setSelectedRegion(region)} + > +
{region.region}
+
+ {region.disasterType.join(", ") || "Extreme conditions"} +
+
+ )) + )} +
+
+ + {/* All Regions */} + +

All Regions

+
+ {weatherData.map((region) => ( +
setSelectedRegion(region)} + > +
+ {region.region} +
+
+
{region.state}
+
+ ))} +
+ +
+
+
+ )} +
+
+ + {showInventoryForm && setShowInventoryForm(false)} onSubmit={handleAddInventory} />} + + {editingItem && ( + setEditingItem(null)} onSubmit={handleEditInventory} /> + )} + + {updatingItem && ( + setUpdatingItem(null)} + onUpdate={handleUpdateQuantity} + /> + )} +
+ ) +} + +declare global { + interface Window { + L: any + } +} diff --git a/submission/program/app/page.tsx b/submission/program/app/page.tsx new file mode 100644 index 00000000..139465de --- /dev/null +++ b/submission/program/app/page.tsx @@ -0,0 +1,425 @@ +import Link from "next/link" +import { Button } from "@/components/ui/button" +import { Card } from "@/components/ui/card" +import { HeartHandshake, Users, MapPin, Package, TrendingUp, Shield, Zap, Globe, Map, Briefcase } from "lucide-react" +import Image from "next/image" + +export default function HomePage() { + return ( +
+ {/* Header */} +
+
+
+
+ +
+ SAHAARA +
+ +
+ + + + + + + + + +
+
+
+ + {/* Hero Section */} +
+
+ Disaster relief workers distributing aid to affected communities +
+
+

+ Connecting communities in crisis with coordinated relief +

+

+ A centralized platform for India that bridges the gap between disaster-affected communities and NGOs with + real-time weather monitoring, ensuring faster response, transparent coordination, and efficient resource + distribution. +

+
+ + + + + + + + + + + + +
+
+
+ + {/* Stats Section */} +
+
+
+
+
Real-time
+
Response Coordination
+
+
+
100%
+
Transparent Tracking
+
+
+
Zero
+
Duplication of Efforts
+
+
+
Global
+
Scalable Platform
+
+
+
+
+ + {/* How It Works */} +
+
+

How It Works

+

+ Three interconnected portals working together to save lives and coordinate relief efforts +

+
+ +
+ +
+ Community members receiving relief supplies +
+
+ +
+

Community Portal

+

+ Public-facing platform where affected communities can voice their urgent needs directly. +

+
    +
  • +
    + Post urgent needs with location and time tags +
  • +
  • +
    + Request specific items or volunteer help +
  • +
  • +
    + Track request status in real-time +
  • +
  • +
    + View available resources nearby +
  • +
+
+ + +
+ NGO workers coordinating relief operations +
+
+ +
+

NGO Dashboard

+

+ Secure platform for NGOs to coordinate relief efforts and manage resources efficiently. +

+
    +
  • +
    + Access real-time needs feed by location +
  • +
  • +
    + Track inventory and resource availability +
  • +
  • +
    + Claim and fulfill requests efficiently +
  • +
  • +
    + Coordinate with other NGOs to avoid duplication +
  • +
+
+ + +
+ Professional volunteers coordinating relief +
+
+ +
+

Professional Recruitment

+

+ Connect skilled professionals with disaster relief opportunities to maximize impact. +

+
    +
  • +
    + Match professionals with urgent skill needs +
  • +
  • +
    + Coordinate medical, engineering, and logistics experts +
  • +
  • +
    + Track volunteer hours and certifications +
  • +
  • +
    + Build a network of trained disaster responders +
  • +
+
+
+
+ + {/* Features */} +
+
+
+

Key Features

+

+ Built for speed, transparency, and effective coordination during critical times +

+
+ +
+ + +

Weather Monitoring

+

+ Real-time weather data and disaster risk assessment across Indian regions with interactive maps +

+
+ + + +

Location-Based

+

+ All requests tagged with precise location data for efficient resource allocation +

+
+ + + +

Real-Time Updates

+

+ Instant notifications and status updates for both communities and NGOs +

+
+ + + +

Inventory Tracking

+

+ Comprehensive resource management to prevent waste and duplication +

+
+ + + +

Analytics Dashboard

+

+ Data-driven insights to optimize relief operations and measure impact +

+
+ + + +

Secure & Verified

+

+ Verified NGO access and credible community requests with time stamps +

+
+ + + +

Professional Network

+

+ Connect skilled professionals with disaster relief opportunities +

+
+ + + +

Globally Scalable

+

+ Built to scale from local disasters to global humanitarian crises +

+
+
+
+
+ + {/* Impact */} +
+
+

Expected Impact

+

+ Transforming disaster response through technology and coordination +

+
+ +
+ Successful disaster relief distribution showing impact +
+ +
+
+
+ +
+

Faster Response

+

+ Real-time visibility into community needs enables immediate action and reduces response time +

+
+ +
+
+ +
+

Transparent System

+

+ Complete visibility into donations, volunteer efforts, and resource distribution builds trust +

+
+ +
+
+ +
+

Better Coordination

+

+ NGOs work together instead of in silos, eliminating duplication and maximizing impact +

+
+
+
+ + {/* CTA Section */} +
+
+
+

+ Ready to make a difference? +

+

+ Whether you need help or want to provide it, SAHAARA is here to coordinate effective disaster response + across India. +

+
+ + + + + + + + + +
+
+
+
+ + {/* Footer */} +
+
+
+
+
+ +
+ SAHAARA - Disaster Relief Management Platform +
+
Built for humanity, powered by coordination
+
+
+
+
+ ) +} diff --git a/submission/program/app/recruitment/page.tsx b/submission/program/app/recruitment/page.tsx new file mode 100644 index 00000000..e6d6da89 --- /dev/null +++ b/submission/program/app/recruitment/page.tsx @@ -0,0 +1,334 @@ +"use client" + +import type React from "react" + +import { useState } from "react" +import Link from "next/link" +import { Button } from "@/components/ui/button" +import { Card } from "@/components/ui/card" +import { Input } from "@/components/ui/input" +import { Textarea } from "@/components/ui/textarea" +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" +import { Badge } from "@/components/ui/badge" +import { HeartHandshake, ArrowLeft, UserPlus, Stethoscope, HardHat, Truck, Users } from "lucide-react" + +export default function RecruitmentPage() { + const [formData, setFormData] = useState({ + name: "", + email: "", + phone: "", + profession: "", + specialization: "", + experience: "", + location: "", + availability: "", + certifications: "", + languages: "", + motivation: "", + }) + + const [submitted, setSubmitted] = useState(false) + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault() + // Store in localStorage for demo + const professionals = JSON.parse(localStorage.getItem("professionals") || "[]") + professionals.push({ + ...formData, + id: Date.now().toString(), + registeredAt: new Date().toISOString(), + status: "pending", + }) + localStorage.setItem("professionals", JSON.stringify(professionals)) + setSubmitted(true) + } + + const handleChange = (field: string, value: string) => { + setFormData((prev) => ({ ...prev, [field]: value })) + } + + if (submitted) { + return ( +
+ +
+ +
+

Registration Successful!

+

+ Thank you for registering as a professional volunteer. Our team will review your application and contact you + when opportunities matching your skills become available. +

+
+ + + + +
+
+
+ ) + } + + return ( +
+ {/* Header */} +
+
+ +
+ +
+ SAHAARA + + + + +
+
+ +
+ {/* Hero Section */} +
+
+ +
+

Professional Volunteer Registration

+

+ Join our network of skilled professionals ready to respond to disaster relief operations across India +

+
+ + {/* Professional Categories */} +
+ + +
Medical
+
Doctors, Nurses, Paramedics
+
+ + +
Engineering
+
Civil, Structural, Electrical
+
+ + +
Logistics
+
Supply Chain, Transport
+
+ + +
Coordination
+
Management, Communication
+
+
+ + {/* Registration Form */} + +
+ {/* Personal Information */} +
+

Personal Information

+
+
+ + handleChange("name", e.target.value)} + placeholder="Dr. Rajesh Kumar" + /> +
+
+ + handleChange("email", e.target.value)} + placeholder="rajesh.kumar@example.com" + /> +
+
+ + handleChange("phone", e.target.value)} + placeholder="+91 98765 43210" + /> +
+
+ + handleChange("location", e.target.value)} + placeholder="Mumbai, Maharashtra" + /> +
+
+
+ + {/* Professional Details */} +
+

Professional Details

+
+
+ + +
+
+ + handleChange("specialization", e.target.value)} + placeholder="e.g., Emergency Medicine, Structural Assessment" + /> +
+
+ + +
+
+ + +
+
+
+ + {/* Additional Information */} +
+

Additional Information

+
+
+ +