import React, { useMemo, useState } from "react"; import { motion, AnimatePresence } from "framer-motion"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Input } from "@/components/ui/input"; import { Switch } from "@/components/ui/switch"; import { Separator } from "@/components/ui/separator"; import { AlertTriangle, CheckCircle2, Clock, MapPin, TrendingUp, Building2, Wrench, Search, Filter, ChevronRight, ShieldAlert, Truck, Lightbulb, } from "lucide-react"; import { ResponsiveContainer, LineChart, Line, XAxis, YAxis, Tooltip, BarChart, Bar, } from "recharts"; // --- Mock data (replace with API later) --- const DISTRICTS = ["All districts", "Mitte", "Nord", "Süd", "West", "Ost"]; const CATEGORIES = [ "All categories", "Waste", "Roads", "Lighting", "Noise", "Parking", "Water", ]; const kpisBase = { openedToday: 184, closedToday: 159, backlog: 1328, slaBreaches: 42, repeatIncidents: 61, medianResolveHours: 38, citizenSatisfaction: 4.1, }; const trendResolve = [ { week: "W-3", hours: 44 }, { week: "W-2", hours: 41 }, { week: "W-1", hours: 39 }, { week: "This", hours: 38 }, ]; const backlogAging = [ { bucket: "0–2d", count: 424 }, { bucket: "3–7d", count: 366 }, { bucket: "8–30d", count: 401 }, { bucket: "30d+", count: 137 }, ]; const hotspots = [ { id: "HS-101", district: "Nord", category: "Waste", title: "Overflowing bins near transit stop", location: "Rosenweg 12", ageDays: 6, priority: "High", repeats: 3, }, { id: "HS-102", district: "Mitte", category: "Lighting", title: "Streetlights out on main crossing", location: "Alexanderplatz East", ageDays: 2, priority: "Critical", repeats: 1, }, { id: "HS-103", district: "Süd", category: "Roads", title: "Potholes expanding after rain", location: "Bergstraße 7–15", ageDays: 11, priority: "High", repeats: 2, }, { id: "HS-104", district: "West", category: "Parking", title: "Illegal parking blocking fire lane", location: "Kantstraße 22", ageDays: 1, priority: "Medium", repeats: 4, }, ]; const demandSupply = [ { district: "Nord", category: "Waste", demandScore: 86, supplyScore: 42, gap: 44, note: "Contractors concentrated in Mitte; long travel times", }, { district: "Süd", category: "Roads", demandScore: 74, supplyScore: 51, gap: 23, note: "Asphalt crew scheduled; permitting delays", }, { district: "Mitte", category: "Lighting", demandScore: 61, supplyScore: 68, gap: -7, note: "Healthy coverage; parts inventory is bottleneck", }, { district: "West", category: "Parking", demandScore: 70, supplyScore: 33, gap: 37, note: "Enforcement staff shortage; peak weekend loads", }, ]; const providers = [ { id: "P-201", name: "NordClean GmbH", category: "Waste", district: "Nord", license: "Verified", etaHours: 6, rating: 4.6, capacity: "High", }, { id: "P-202", name: "CityLight Service", category: "Lighting", district: "Mitte", license: "Verified", etaHours: 10, rating: 4.3, capacity: "Medium", }, { id: "P-203", name: "WestPark Patrol", category: "Parking", district: "West", license: "Pending", etaHours: 12, rating: 4.0, capacity: "Low", }, { id: "P-204", name: "Bergstraße Asphalt", category: "Roads", district: "Süd", license: "Verified", etaHours: 18, rating: 4.4, capacity: "Medium", }, ]; function clamp(n, min, max) { return Math.max(min, Math.min(max, n)); } function priorityBadge(priority) { const base = "rounded-full"; if (priority === "Critical") return {priority}; if (priority === "High") return {priority}; return {priority}; } function formatHours(h) { if (h < 24) return `${h}h`; const d = Math.round((h / 24) * 10) / 10; return `${d}d`; } function SmallKPI({ icon: Icon, label, value, hint, tone = "default" }) { const toneClass = tone === "danger" ? "border-destructive/30" : tone === "good" ? "border-emerald-500/20" : "border-border"; return (
{label}
{value}
{hint ? (
{hint}
) : null}
); } function RowBar({ label, left, right }) { const total = Math.max(1, left + right); const leftPct = (left / total) * 100; return (
{label} {left} / {right}
); } export default function TurashCityDashboardPrototype() { const [district, setDistrict] = useState("All districts"); const [category, setCategory] = useState("All categories"); const [query, setQuery] = useState(""); const [publicMode, setPublicMode] = useState(false); const [selectedHotspot, setSelectedHotspot] = useState(null); const [budgetBoost, setBudgetBoost] = useState(12); // percent const filteredHotspots = useMemo(() => { return hotspots .filter((h) => (district === "All districts" ? true : h.district === district)) .filter((h) => (category === "All categories" ? true : h.category === category)) .filter((h) => { if (!query.trim()) return true; const q = query.toLowerCase(); return ( h.title.toLowerCase().includes(q) || h.location.toLowerCase().includes(q) || h.id.toLowerCase().includes(q) ); }); }, [district, category, query]); const suggestedProviders = useMemo(() => { if (!selectedHotspot) return []; const c = selectedHotspot.category; const d = selectedHotspot.district; return providers .filter((p) => p.category === c) .sort((a, b) => { const aMatch = a.district === d ? 0 : 1; const bMatch = b.district === d ? 0 : 1; if (aMatch !== bMatch) return aMatch - bMatch; return a.etaHours - b.etaHours; }) .slice(0, 4); }, [selectedHotspot]); const simulated = useMemo(() => { // ultra-simplified “scenario”: more budget reduces median resolution and SLA breaches const factor = budgetBoost / 100; const median = Math.round(kpisBase.medianResolveHours *(1 - 0.35* factor)); const breaches = Math.round(kpisBase.slaBreaches *(1 - 0.55* factor)); const satisfaction = Math.round((kpisBase.citizenSatisfaction + 0.35 *factor)* 10) / 10; return { medianResolveHours: clamp(median, 18, 60), slaBreaches: clamp(breaches, 8, 80), citizenSatisfaction: clamp(satisfaction, 3.2, 4.8), }; }, [budgetBoost]); return (
{/*Header*/}

Turash — City Management Cockpit

Prototype

Operational awareness + vendor routing + economic insight (one thin layer, no 12‑month IT project).

Public dashboard
{/* Filters */}
Filters
setQuery(e.target.value)} placeholder="Search issue id, location, title…" className="rounded-2xl pl-9" />
Last updated: just now (mock) Sources: 311 intake, permits, vendor registry Data quality: medium (2 integrations pending)
{/* KPIs */}
{/* Tabs */}
Pulse Service performance Economy & supply {/* PULSE */}
Incident hotspots (map) Heatmap + what changed vs last week. Click a hotspot to route work.
Map placeholder
{district}
Heat
↑ 12%
New clusters
3
Critical
7
Repeat sites
{kpisBase.repeatIncidents}
In real deployments, this panel uses your GIS tile server or a lightweight map SDK.
Top hotspots Sorted by priority × age × repeats
{filteredHotspots.map((h) => ( ))} {filteredHotspots.length === 0 ? (
No hotspots match the current filters.
) : null}
{/* Side panel */} {selectedHotspot ? (
Selected hotspot Route work to local providers; track completion + citizen satisfaction.
{selectedHotspot.title}
{priorityBadge(selectedHotspot.priority)} {selectedHotspot.id}
Location
{selectedHotspot.location}
District
{selectedHotspot.district}
Category
{selectedHotspot.category}
Age
{selectedHotspot.ageDays} days
Repeats
{selectedHotspot.repeats}
SLA
{selectedHotspot.priority === "Critical" ? "24h" : "72h"}
Escalation
{selectedHotspot.ageDays > 7 ? "Yes" : "No"}
Root cause hint
This is the kind of “repeat incident” flag city leadership reacts to: same site keeps resurfacing. Turash can propose a systemic fix and show cost-to-serve if left unresolved.
Suggested providers
Local-first
{suggestedProviders.map((p) => (
{p.name}
{p.category} • {p.district} • {p.license}
ETA {formatHours(p.etaHours)}
Rating
{p.rating}
Capacity
{p.capacity}
ID
{p.id}
))} {suggestedProviders.length === 0 ? (
No matching providers found. (This is a procurement-gap signal.)
) : null}
Micro-procurement mode
Turn small jobs into fast routing — without replacing the city’s procurement system.
) : null}
{/* SERVICE PERFORMANCE */}
Median resolution time (4 weeks) What leadership cares about: trend direction + exceptions Backlog aging Where the system is silently failing
Department performance (example) Simple, comparable, action-driving metrics
Escalation rule (example)
If backlog 30d+ grows for 2 consecutive weeks → auto-create an escalation brief with cost & hotspot list.
Scenario slider Budget → measurable outcomes (simple, honest)
Ops budget increase
+{budgetBoost}%
setBudgetBoost(parseInt(e.target.value, 10))} />
Median resolve time
{simulated.medianResolveHours}h
SLA breaches
{simulated.slaBreaches}
Citizen satisfaction
{simulated.citizenSatisfaction} / 5
This stays credible if you keep it conservative and show confidence bands once you have data.
{/* ECONOMY & SUPPLY */}
Demand–Supply Gap (by district × category) Your wedge: connect city needs to local supplier capacity — and prove “local-first” works.
{demandSupply .filter((r) => (district === "All districts" ? true : r.district === district)) .filter((r) => (category === "All categories" ? true : r.category === category)) .map((r, idx) => (
{r.district}
{r.category} Gap {r.gap > 0 ? `+${r.gap}` : r.gap}
{r.note}
Demand
{r.demandScore}
Supply
{r.supplyScore}
Operational implication
High gap → longer ETAs and SLA breaches unless you re-balance coverage.
Economic implication
Gap is a target list for SME support / attracting providers.
Suggested action
Broadcast micro-jobs + verify local suppliers + track completion quality.
))}
If this becomes real: your hardest part is *vendor registry accuracy* (licenses, categories, coverage, availability). Don’t fake it — design the workflow to improve data quality over time.
Business ecosystem signals Politically useful, but must be defensible
New openings (30d)
+28
Most: food service, repairs, local retail
Permit pipeline
312
Avg approval: 9.6 days • 18 blocked
Local-first share
62%
Share of routed work completed by local providers
What makes this credible
  • Show your sources (permits, registry, verified vendors)
  • Separate “estimated” from “measured”
  • Keep numbers conservative until you have time-series evidence
Next best feature for Turash
“Broadcast micro-jobs” + vendor verification loop → grows supply data as a side effect.
{/* Footer note */}
Prototype intent: demonstrate the *feel* and “why it wins.” Replace mock data with your APIs, then keep the surface area small.
); } Which information do you think city management should be seing and what would be useful and appealing for turash project Thought for 8s City management doesn’t want “more data”. They want situational awareness + accountability + budget justification in one screen. If Turash can give them that (without a 12-month IT project), it’s appealing. What they should be seeing (the “executive cockpit”) These are the few things mayors / city managers actually act on: City pulse (today / this week) of citizen issues opened/closed (311-style), backlog, SLA breaches Top 5 problem categories trending (waste, roads, lighting, noise, parking) Hotspots on a map (heatmap + “what changed vs last week”) Service performance (accountability) Median time-to-resolve by department and category “Aging” of open issues (0–2d, 3–7d, 8–30d, 30+d) Repeat incidents (same location/category reappearing = systemic failure) Budget impact (the language of decisions) Cost-to-serve per category (even rough ranges) Overtime spend, contractor spend, unit costs (€/pothole, €/lamp repair) “If we fund X, SLA improves by Y” (simple scenario sliders) Economic activity (politically valuable) New business openings/closures by district Permit pipeline (submitted/approved/blocked + time in each stage) Local business engagement: demand vs supply gaps (more below) Risk & compliance (things that explode later) Safety hazards unresolved (sidewalk/lighting/traffic) Critical infrastructure incidents (water leaks, power issues) Compliance queue (inspections, deadlines, renewals) What’s uniquely useful for Turash (your edge) Turash sounds like a city CRM + local business graph. Your unfair advantage is connecting problems → local suppliers → resolution. City management will care about: A) “Demand–Supply Gap” map (killer feature) Show where citizens/municipal needs exist but local supply is missing or overloaded: Example: lots of complaints about waste pickup in District A + few active waste contractors there Or: high renovation permits + not enough licensed electricians This is gold for: Economic development (attract suppliers) Procurement strategy (reduce response time) Policy (support training programs in shortage trades) B) Procurement-lite routing (without calling it procurement) Cities hate “new procurement systems”. But they love: “Suggested local vendors for this job category (licensed, available, near)” “Broadcast small jobs to verified local providers” “Track acceptance, completion, and citizen satisfaction” That’s a real operational wedge. C) Business ecosystem health (simple, visual, political) “Top 10 categories growing / shrinking” “Vacancy signals” (if you can proxy: listings, footfall, complaints, closures) “Local spend kept local” estimate (even directional) The 12 widgets that sell the product in 5 minutes If you want a demo dashboard that lands, build these first: Open issues today / closed today SLA breach counter + top violating departments Backlog aging histogram Heatmap of incidents with category filters Repeat-problem locations list (top 20) Median resolution time trend (4-week) Permit funnel + average approval time Business openings/closures by district Demand–supply gap map by category “Suggested providers” for a selected issue (with distance/licensing) Citizen satisfaction score after closure (1–5) Cost estimate: “this month’s service workload” vs last month Hard truth: cities won’t integrate 20 systems for your MVP Assumption to kill early: “we’ll ingest all city data”. You won’t—at least not at first. Win with a thin layer: Start with one workflow (e.g., citizen issues + routing to local contractors) Use manual import / CSV / email parsing / simple API initially Prove: backlog down, resolution faster, local providers engaged Once they see impact, integration budgets appear. What will be “appealing” internally (how they justify buying) Frame your outputs as: SLA improvement (measurable) Lower cost-to-serve (even directional) Economic uplift (support local SMEs, reduce outside contractors) Transparency (public dashboard option, if they’re brave) If you tell me who the buyer is (mayor’s office, economic development, operations, or a “smart city” unit) and what Turash currently has (business directory only? CRM? issue tracking?), I’ll pin this down into a tight MVP scope and a demo flow that closes. Can you design example in web canvas to get the feel Thought for 12s Done — I sketched a Turash “City Management Cockpit” React prototype in canvas: filters (district/category/search), KPI row, and 3 tabs: Pulse: hotspot list + “map” placeholder + click-to-open routing panel with suggested providers Service performance: resolution-time trend + backlog aging + a conservative scenario slider (budget → SLA impact) Economy & supply: Demand–Supply Gap view + “business signals” card (defensible, not fluffy) Tell me which persona you want to optimize for first (Mayor / Ops director / Economic development / IT) and I’ll reshape the layout and the “default story” of the dashboard accordingly. ChatGPT can make mistakes. Check important info. See Cookie Preferences.