Files
Codewalkers/apps/web/src/components/DecisionList.tsx
Lukas May 34578d39c6 refactor: Restructure monorepo to apps/server/ and apps/web/ layout
Move src/ → apps/server/ and packages/web/ → apps/web/ to adopt
standard monorepo conventions (apps/ for runnable apps, packages/
for reusable libraries). Update all config files, shared package
imports, test fixtures, and documentation to reflect new paths.

Key fixes:
- Update workspace config to ["apps/*", "packages/*"]
- Update tsconfig.json rootDir/include for apps/server/
- Add apps/web/** to vitest exclude list
- Update drizzle.config.ts schema path
- Fix ensure-schema.ts migration path detection (3 levels up in dev,
  2 levels up in dist)
- Fix tests/integration/cli-server.test.ts import paths
- Update packages/shared imports to apps/server/ paths
- Update all docs/ files with new paths
2026-03-03 11:22:53 +01:00

97 lines
2.8 KiB
TypeScript

import { useState } from "react";
import { ChevronDown, ChevronRight } from "lucide-react";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
export interface Decision {
topic: string;
decision: string;
reason: string;
}
interface DecisionListProps {
decisions: Decision[];
maxVisible?: number;
}
export function DecisionList({ decisions, maxVisible = 3 }: DecisionListProps) {
const [expandedIndices, setExpandedIndices] = useState<Set<number>>(
new Set()
);
const [showAll, setShowAll] = useState(false);
function toggleDecision(index: number) {
setExpandedIndices((prev) => {
const next = new Set(prev);
if (next.has(index)) {
next.delete(index);
} else {
next.add(index);
}
return next;
});
}
const visibleDecisions = showAll
? decisions
: decisions.slice(0, maxVisible);
const hasMore = decisions.length > maxVisible;
return (
<Card>
<CardHeader>
<CardTitle className="text-base">Key Decisions</CardTitle>
</CardHeader>
<CardContent>
{decisions.length === 0 ? (
<p className="text-sm text-muted-foreground">
No decisions recorded
</p>
) : (
<div className="space-y-1">
{visibleDecisions.map((d, i) => {
const isExpanded = expandedIndices.has(i);
return (
<div key={i}>
<button
type="button"
className="flex w-full items-center gap-2 rounded px-2 py-1.5 text-left text-sm font-medium hover:bg-accent/50"
onClick={() => toggleDecision(i)}
>
{isExpanded ? (
<ChevronDown className="h-4 w-4 shrink-0 text-muted-foreground" />
) : (
<ChevronRight className="h-4 w-4 shrink-0 text-muted-foreground" />
)}
{d.topic}
</button>
{isExpanded && (
<div className="ml-8 space-y-1 pb-2 text-sm">
<p>{d.decision}</p>
<p className="text-muted-foreground">
Reason: {d.reason}
</p>
</div>
)}
</div>
);
})}
{hasMore && (
<Button
variant="ghost"
size="sm"
className="mt-1 w-full"
onClick={() => setShowAll((prev) => !prev)}
>
{showAll
? "Show less"
: `Show ${decisions.length - maxVisible} more`}
</Button>
)}
</div>
)}
</CardContent>
</Card>
);
}