Files
Codewalkers/apps/web/src/components/InboxDetailPanel.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

172 lines
4.6 KiB
TypeScript

import { Link } from "@tanstack/react-router";
import { ChevronLeft } from "lucide-react";
import { Button } from "@/components/ui/button";
import { QuestionForm } from "@/components/QuestionForm";
import { formatRelativeTime } from "@/lib/utils";
interface InboxDetailPanelProps {
agent: {
id: string;
name: string;
status: string;
taskId: string | null;
updatedAt: string;
};
message: {
id: string;
content: string;
requiresResponse: boolean;
} | null;
questions:
| {
id: string;
question: string;
options: any;
multiSelect: boolean;
}[]
| null;
isLoadingQuestions: boolean;
questionsError: string | null;
onBack: () => void;
onSubmitAnswers: (answers: Record<string, string>) => void;
onDismissQuestions: () => void;
onDismissMessage: () => void;
isSubmitting: boolean;
isDismissingQuestions: boolean;
isDismissingMessage: boolean;
submitError: string | null;
dismissMessageError: string | null;
}
export function InboxDetailPanel({
agent,
message,
questions,
isLoadingQuestions,
questionsError,
onBack,
onSubmitAnswers,
onDismissQuestions,
onDismissMessage,
isSubmitting,
isDismissingQuestions,
isDismissingMessage,
submitError,
dismissMessageError,
}: InboxDetailPanelProps) {
return (
<div className="space-y-4 rounded-lg border border-border p-4">
{/* Mobile back button */}
<Button
variant="ghost"
size="sm"
className="lg:hidden"
onClick={onBack}
>
<ChevronLeft className="mr-1 h-4 w-4" />
Back to list
</Button>
{/* Detail Header */}
<div className="border-b border-border pb-3">
<div className="flex items-center justify-between">
<h3 className="text-sm font-bold">
{agent.name}{" "}
<span className="font-normal text-muted-foreground">
&rarr; You
</span>
</h3>
<span className="text-xs text-muted-foreground">
{formatRelativeTime(agent.updatedAt)}
</span>
</div>
<p className="mt-1 text-xs text-muted-foreground">
Task:{" "}
{agent.taskId ? (
<Link
to="/initiatives"
className="text-primary hover:underline"
>
{agent.taskId}
</Link>
) : (
"\u2014"
)}
</p>
{agent.taskId && (
<Link
to="/initiatives"
className="mt-1 inline-block text-xs text-primary hover:underline"
>
View in context &rarr;
</Link>
)}
</div>
{/* Question Form or Notification Content */}
{isLoadingQuestions && (
<div className="py-4 text-center text-sm text-muted-foreground">
Loading questions...
</div>
)}
{questionsError && (
<div className="py-4 text-center text-sm text-destructive">
Failed to load questions: {questionsError}
</div>
)}
{questions && questions.length > 0 && (
<QuestionForm
questions={questions}
onSubmit={onSubmitAnswers}
onCancel={onBack}
onDismiss={onDismissQuestions}
isSubmitting={isSubmitting}
isDismissing={isDismissingQuestions}
/>
)}
{submitError && (
<p className="text-sm text-destructive">Error: {submitError}</p>
)}
{/* Notification message (no questions / requiresResponse=false) */}
{message && !message.requiresResponse && !isLoadingQuestions && (
<div className="space-y-3">
<p className="text-sm">{message.content}</p>
<div className="flex justify-end">
<Button
variant="outline"
size="sm"
onClick={onDismissMessage}
disabled={isDismissingMessage}
>
{isDismissingMessage ? "Dismissing..." : "Dismiss"}
</Button>
</div>
{dismissMessageError && (
<p className="text-sm text-destructive">
Error: {dismissMessageError}
</p>
)}
</div>
)}
{/* No questions and requires response -- message content only */}
{message &&
message.requiresResponse &&
questions &&
questions.length === 0 &&
!isLoadingQuestions && (
<div className="space-y-3">
<p className="text-sm">{message.content}</p>
<p className="text-xs text-muted-foreground">
Waiting for structured questions...
</p>
</div>
)}
</div>
);
}