mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-14 17:43:04 +00:00
436 seeded Praças (municipality-based; per-TSE-zone in Salvador/Camaçari) become the operational unit; roles renamed to coordinator/advisor/leader with advisors scoped to administered Praças. Leadership is one record per person across many Praças/organizations; vote pledges split leader-declared vs staff-estimated (estimates never serialized to leaders). Adds organizations, demand workflow with staff-only cost/receipts, action-plan results with deputy presence, manual political trend, multi-candidate comparison and the diverging red/white/blue map mode. Migration 20260721_020109_remodel_plazas deliberately resets the campaign vertical in production (public site untouched); test suite ported to the new model (unit 187 / int 306 / e2e 9 green).
55 lines
2.3 KiB
TypeScript
55 lines
2.3 KiB
TypeScript
import Link from 'next/link'
|
|
import { CalendarIcon, MapPinIcon, UserIcon } from 'lucide-react'
|
|
|
|
import { ActionPlanStatusBadge } from '@/components/campaign/ActionPlanStatusBadge'
|
|
import { Badge } from '@/components/ui/Badge'
|
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
|
import { actionPlanKindLabels } from '@/lib/schemas/actionPlan'
|
|
import { formatBahiaDateTimeLabel } from '@/utilities/campaignTime'
|
|
import type { ActionPlanListViewModel } from '@/utilities/actionPlanViewModels'
|
|
|
|
const formatWhen = (plan: ActionPlanListViewModel): string =>
|
|
plan.startAt ? formatBahiaDateTimeLabel(plan.startAt) : 'Data a definir'
|
|
|
|
export const ActionPlanCard = ({ plan }: { plan: ActionPlanListViewModel }) => (
|
|
<Card>
|
|
<CardHeader>
|
|
<div className="flex flex-wrap items-center gap-2">
|
|
<Badge variant="secondary">{actionPlanKindLabels[plan.kind]}</Badge>
|
|
<ActionPlanStatusBadge status={plan.status} />
|
|
{plan.deputyPresent ? <Badge>Deputado presente</Badge> : null}
|
|
</div>
|
|
<CardTitle>
|
|
<Link
|
|
href={`/campanha/planos/${plan.slug}`}
|
|
className="text-foreground underline-offset-4 hover:underline"
|
|
>
|
|
{plan.title}
|
|
</Link>
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent className="flex flex-col gap-2">
|
|
<div className="flex items-center gap-1.5 text-sm text-muted-foreground">
|
|
<CalendarIcon aria-hidden="true" className="size-4 shrink-0" />
|
|
<span>{formatWhen(plan)}</span>
|
|
</div>
|
|
{plan.locationLabel ? (
|
|
<div className="flex items-center gap-1.5 text-sm text-muted-foreground">
|
|
<MapPinIcon aria-hidden="true" className="size-4 shrink-0" />
|
|
<Badge variant="outline">{plan.locationLabel}</Badge>
|
|
</div>
|
|
) : null}
|
|
<div className="flex flex-wrap items-center justify-between gap-2 pt-1 text-sm">
|
|
<span className="flex items-center gap-1.5 text-muted-foreground">
|
|
<UserIcon aria-hidden="true" className="size-4 shrink-0" />
|
|
Resp: {plan.responsibleName ?? 'Não definido'}
|
|
</span>
|
|
{plan.taskProgress.total > 0 ? (
|
|
<span className="font-medium tabular-nums text-muted-foreground">
|
|
{plan.taskProgress.done}/{plan.taskProgress.total} tarefas
|
|
</span>
|
|
) : null}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
)
|